@Test public void testCubicFunctionRoots() { List<Double> roots; roots = SumatraMath.cubicFunctionRoots(0, 1, 6, 5); Assert.assertTrue(roots.size() == 2); Assert.assertEquals(-1.0, roots.get(0), 1e-6); Assert.assertEquals(-5.0, roots.get(1), 1e-6); roots = SumatraMath.cubicFunctionRoots(1, 2, 3, 4); Assert.assertTrue(roots.size() == 1); Assert.assertEquals(-1.650629191439386, roots.get(0), 1e-6); roots = SumatraMath.cubicFunctionRoots(1, -8, 3, 4); Assert.assertTrue(roots.size() == 3); Assert.assertEquals(7.531128874149275, roots.get(0), 1e-6); Assert.assertEquals(-0.5311288741492746, roots.get(1), 1e-6); Assert.assertEquals(1.0, roots.get(2), 1e-6); roots = SumatraMath.cubicFunctionRoots(1, -8, 0, 0); Assert.assertTrue(roots.size() == 2); Assert.assertEquals(8.0, roots.get(0), 1e-6); Assert.assertEquals(0.0, roots.get(1), 1e-6); roots = SumatraMath.cubicFunctionRoots(2, 14, 32, 24); Assert.assertTrue(roots.size() == 2); Assert.assertEquals(-3, roots.get(0), 1e-6); Assert.assertEquals(-2, roots.get(1), 1e-6); roots = SumatraMath.cubicFunctionRoots(2, -11, 20, -12); Assert.assertTrue(roots.size() == 2); Assert.assertEquals(1.5, roots.get(0), 1e-6); Assert.assertEquals(2, roots.get(1), 1e-6); }
public static List<Double> cubicFunctionRoots(final double a3, final double b2, final double c1, final double d0) { if (isEqual(a3, 0.0)) { return quadraticFunctionRoots(b2, c1, d0); } List<Double> roots = new ArrayList<>(); double a = b2 / a3; double b = c1 / a3; double c = d0 / a3; double aOver3 = a / 3.0; double q = ((3 * b) - (a * a)) / 9.0; double qCube = q * q * q; double r = ((9 * a * b) - (27 * c) - (2 * a * a * a)) / 54.0; double rSqr = r * r; double d = qCube + rSqr; if (d < 0.0) { double theta = SumatraMath.acos(r / SumatraMath.sqrt(-qCube)); double sqrtQ = SumatraMath.sqrt(-q); double x1 = (2.0 * sqrtQ * SumatraMath.cos(theta / 3.0)) - aOver3; double x2 = (2.0 * sqrtQ * SumatraMath.cos((theta + AngleMath.PI_TWO) / 3.0)) - aOver3; double x3 = (2.0 * sqrtQ * SumatraMath.cos((theta + (AngleMath.PI * 4.0)) / 3.0)) - aOver3; roots.add(x1); roots.add(x2); roots.add(x3); } else if (d > 0.0) { double sqrtD = SumatraMath.sqrt(d); double s = Math.cbrt(r + sqrtD); double t = Math.cbrt(r - sqrtD); double x1 = (s + t) - aOver3; roots.add(x1); } else { double cbrtR = Math.cbrt(r); double x1 = (2 * cbrtR) - aOver3; double x2 = -cbrtR - aOver3; roots.add(x1); roots.add(x2); } return roots; }
SumatraMath { public static List<Double> cubicFunctionRoots(final double a3, final double b2, final double c1, final double d0) { if (isEqual(a3, 0.0)) { return quadraticFunctionRoots(b2, c1, d0); } List<Double> roots = new ArrayList<>(); double a = b2 / a3; double b = c1 / a3; double c = d0 / a3; double aOver3 = a / 3.0; double q = ((3 * b) - (a * a)) / 9.0; double qCube = q * q * q; double r = ((9 * a * b) - (27 * c) - (2 * a * a * a)) / 54.0; double rSqr = r * r; double d = qCube + rSqr; if (d < 0.0) { double theta = SumatraMath.acos(r / SumatraMath.sqrt(-qCube)); double sqrtQ = SumatraMath.sqrt(-q); double x1 = (2.0 * sqrtQ * SumatraMath.cos(theta / 3.0)) - aOver3; double x2 = (2.0 * sqrtQ * SumatraMath.cos((theta + AngleMath.PI_TWO) / 3.0)) - aOver3; double x3 = (2.0 * sqrtQ * SumatraMath.cos((theta + (AngleMath.PI * 4.0)) / 3.0)) - aOver3; roots.add(x1); roots.add(x2); roots.add(x3); } else if (d > 0.0) { double sqrtD = SumatraMath.sqrt(d); double s = Math.cbrt(r + sqrtD); double t = Math.cbrt(r - sqrtD); double x1 = (s + t) - aOver3; roots.add(x1); } else { double cbrtR = Math.cbrt(r); double x1 = (2 * cbrtR) - aOver3; double x2 = -cbrtR - aOver3; roots.add(x1); roots.add(x2); } return roots; } }
SumatraMath { public static List<Double> cubicFunctionRoots(final double a3, final double b2, final double c1, final double d0) { if (isEqual(a3, 0.0)) { return quadraticFunctionRoots(b2, c1, d0); } List<Double> roots = new ArrayList<>(); double a = b2 / a3; double b = c1 / a3; double c = d0 / a3; double aOver3 = a / 3.0; double q = ((3 * b) - (a * a)) / 9.0; double qCube = q * q * q; double r = ((9 * a * b) - (27 * c) - (2 * a * a * a)) / 54.0; double rSqr = r * r; double d = qCube + rSqr; if (d < 0.0) { double theta = SumatraMath.acos(r / SumatraMath.sqrt(-qCube)); double sqrtQ = SumatraMath.sqrt(-q); double x1 = (2.0 * sqrtQ * SumatraMath.cos(theta / 3.0)) - aOver3; double x2 = (2.0 * sqrtQ * SumatraMath.cos((theta + AngleMath.PI_TWO) / 3.0)) - aOver3; double x3 = (2.0 * sqrtQ * SumatraMath.cos((theta + (AngleMath.PI * 4.0)) / 3.0)) - aOver3; roots.add(x1); roots.add(x2); roots.add(x3); } else if (d > 0.0) { double sqrtD = SumatraMath.sqrt(d); double s = Math.cbrt(r + sqrtD); double t = Math.cbrt(r - sqrtD); double x1 = (s + t) - aOver3; roots.add(x1); } else { double cbrtR = Math.cbrt(r); double x1 = (2 * cbrtR) - aOver3; double x2 = -cbrtR - aOver3; roots.add(x1); roots.add(x2); } return roots; } private  SumatraMath(); }
SumatraMath { public static List<Double> cubicFunctionRoots(final double a3, final double b2, final double c1, final double d0) { if (isEqual(a3, 0.0)) { return quadraticFunctionRoots(b2, c1, d0); } List<Double> roots = new ArrayList<>(); double a = b2 / a3; double b = c1 / a3; double c = d0 / a3; double aOver3 = a / 3.0; double q = ((3 * b) - (a * a)) / 9.0; double qCube = q * q * q; double r = ((9 * a * b) - (27 * c) - (2 * a * a * a)) / 54.0; double rSqr = r * r; double d = qCube + rSqr; if (d < 0.0) { double theta = SumatraMath.acos(r / SumatraMath.sqrt(-qCube)); double sqrtQ = SumatraMath.sqrt(-q); double x1 = (2.0 * sqrtQ * SumatraMath.cos(theta / 3.0)) - aOver3; double x2 = (2.0 * sqrtQ * SumatraMath.cos((theta + AngleMath.PI_TWO) / 3.0)) - aOver3; double x3 = (2.0 * sqrtQ * SumatraMath.cos((theta + (AngleMath.PI * 4.0)) / 3.0)) - aOver3; roots.add(x1); roots.add(x2); roots.add(x3); } else if (d > 0.0) { double sqrtD = SumatraMath.sqrt(d); double s = Math.cbrt(r + sqrtD); double t = Math.cbrt(r - sqrtD); double x1 = (s + t) - aOver3; roots.add(x1); } else { double cbrtR = Math.cbrt(r); double x1 = (2 * cbrtR) - aOver3; double x2 = -cbrtR - aOver3; roots.add(x1); roots.add(x2); } return roots; } private  SumatraMath(); static double sqrt(final double number); static double square(final double x); static double min(final double... values); static double max(final double... values); static boolean hasDigitsAfterDecimalPoint(final double number); static boolean isEqual(final double a, final double b, final double tolerance); static boolean isEqual(final double a, final double b); static boolean isBetween(final double x, final double min, final double max); static boolean isZero(final double v); static double relative(final double value, final double from, final double to); static double cap(final double value, final double min, final double max); static List<Double> quadraticFunctionRoots(final double a, final double b, final double c); static List<Double> cubicFunctionRoots(final double a3, final double b2, final double c1, final double d0); static double getEqualTol(); static double acos(double x); static double asin(double x); static double atan2(double y, double x); static double cos(double angle); static double sin(double angle); static double tan(double angle); static List<Double> evenDistribution1D(double min, double max, int n); }
SumatraMath { public static List<Double> cubicFunctionRoots(final double a3, final double b2, final double c1, final double d0) { if (isEqual(a3, 0.0)) { return quadraticFunctionRoots(b2, c1, d0); } List<Double> roots = new ArrayList<>(); double a = b2 / a3; double b = c1 / a3; double c = d0 / a3; double aOver3 = a / 3.0; double q = ((3 * b) - (a * a)) / 9.0; double qCube = q * q * q; double r = ((9 * a * b) - (27 * c) - (2 * a * a * a)) / 54.0; double rSqr = r * r; double d = qCube + rSqr; if (d < 0.0) { double theta = SumatraMath.acos(r / SumatraMath.sqrt(-qCube)); double sqrtQ = SumatraMath.sqrt(-q); double x1 = (2.0 * sqrtQ * SumatraMath.cos(theta / 3.0)) - aOver3; double x2 = (2.0 * sqrtQ * SumatraMath.cos((theta + AngleMath.PI_TWO) / 3.0)) - aOver3; double x3 = (2.0 * sqrtQ * SumatraMath.cos((theta + (AngleMath.PI * 4.0)) / 3.0)) - aOver3; roots.add(x1); roots.add(x2); roots.add(x3); } else if (d > 0.0) { double sqrtD = SumatraMath.sqrt(d); double s = Math.cbrt(r + sqrtD); double t = Math.cbrt(r - sqrtD); double x1 = (s + t) - aOver3; roots.add(x1); } else { double cbrtR = Math.cbrt(r); double x1 = (2 * cbrtR) - aOver3; double x2 = -cbrtR - aOver3; roots.add(x1); roots.add(x2); } return roots; } private  SumatraMath(); static double sqrt(final double number); static double square(final double x); static double min(final double... values); static double max(final double... values); static boolean hasDigitsAfterDecimalPoint(final double number); static boolean isEqual(final double a, final double b, final double tolerance); static boolean isEqual(final double a, final double b); static boolean isBetween(final double x, final double min, final double max); static boolean isZero(final double v); static double relative(final double value, final double from, final double to); static double cap(final double value, final double min, final double max); static List<Double> quadraticFunctionRoots(final double a, final double b, final double c); static List<Double> cubicFunctionRoots(final double a3, final double b2, final double c1, final double d0); static double getEqualTol(); static double acos(double x); static double asin(double x); static double atan2(double y, double x); static double cos(double angle); static double sin(double angle); static double tan(double angle); static List<Double> evenDistribution1D(double min, double max, int n);  }