| 612 | } |
| 613 | } |
| 614 | findRoots(f) { |
| 615 | let exp = []; |
| 616 | if (f.type == "polynomial") { |
| 617 | switch (f.values.length - 1) { |
| 618 | case 1: { |
| 619 | exp.push(`${new BigNumber(f.values[1]).isNegative() ? '' : '-'}${f.values[1]} / ${f.values[0]}`) |
| 620 | break; |
| 621 | } |
| 622 | case 2: { |
| 623 | const delta = new BigNumber(f.values[1]).pow(2).minus(new BigNumber(4).times(f.values[0]).times(f.values[2])).toNumber() |
| 624 | if (delta > 0) { |
| 625 | exp.push(`(${new BigNumber(f.values[1]).isNegative() ? '' : '-'}${new BigNumber(f.values[1]).abs()} + Math.sqrt(${delta})) / ${new BigNumber(f.values[0]).times(2)}`) |
| 626 | exp.push(`(${new BigNumber(f.values[1]).isNegative() ? '' : '-'}${new BigNumber(f.values[1]).abs()} - Math.sqrt(${delta})) / ${new BigNumber(f.values[0]).times(2)}`) |
| 627 | } |
| 628 | break; |
| 629 | } |
| 630 | case 3: { |
| 631 | let a = new BigNumber(f.values[0]).toNumber() |
| 632 | let b = new BigNumber(f.values[1]).toNumber() |
| 633 | let c = new BigNumber(f.values[2]).toNumber() |
| 634 | let d = new BigNumber(f.values[3]).toNumber() |
| 635 | |
| 636 | // Convert to depressed cubic t^3+pt+q = 0 (subst x = t - b/3a) |
| 637 | var p = (3 * a * c - b * b) / (3 * a * a); |
| 638 | var q = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a); |
| 639 | var roots; |
| 640 | |
| 641 | if (Math.abs(p) < 1e-8) { // p = 0 -> t^3 = -q -> t = -q^1/3 |
| 642 | roots = [Math.cbrt(-q)]; |
| 643 | } else if (Math.abs(q) < 1e-8) { // q = 0 -> t^3 + pt = 0 -> t(t^2+p)=0 |
| 644 | roots = [0].concat(p < 0 ? [Math.sqrt(-p), -Math.sqrt(-p)] : []); |
| 645 | } else { |
| 646 | var D = q * q / 4 + p * p * p / 27; |
| 647 | |
| 648 | var u; // no-redeclare |
| 649 | if (Math.abs(D) < 1e-8) { // D = 0 -> two roots |
| 650 | roots = [-1.5 * q / p, 3 * q / p]; |
| 651 | } else if (D > 0) { // Only one real root |
| 652 | u = Math.cbrt(-q / 2 - Math.sqrt(D)); |
| 653 | roots = [u - p / (3 * u)]; |
| 654 | } else { // D < 0, three roots, but needs to use complex numbers/trigonometric solution |
| 655 | u = 2 * Math.sqrt(-p / 3); |
| 656 | var t = Math.acos(3 * q / p / u) / 3; // D < 0 implies p < 0 and acos argument in [-1..1] |
| 657 | var k = 2 * Math.PI / 3; |
| 658 | roots = [u * Math.cos(t), u * Math.cos(t - k), u * Math.cos(t - 2 * k)]; |
| 659 | } |
| 660 | } |
| 661 | |
| 662 | // Convert back from depressed cubic |
| 663 | for (var i = 0; i < roots.length; i++) |
| 664 | roots[i] -= b / (3 * a); |
| 665 | exp = roots; |
| 666 | break; |
| 667 | } |
| 668 | default: { |
| 669 | exp = [this.numeralSolve(f, 0)[0]] |
| 670 | } |
| 671 | } |