The Apache Commons Numbers User GuideTable of contentsOverview
The code originated in the commons-math project but was pulled out into a separate project for better maintainability and has since undergone numerous improvements. The library is divided into modules:
The commons-numbers-bom artifact provides a Bill of Materials (BOM) to aid in dependency management of the modules. Examples ModulesIn addition to the modules above, the Commons Numbers source distribution contains example code demonstrating library functionality and/or providing useful development utilities. These modules are not part of the public API of the library and no guarantees are made concerning backwards compatibility. The example module parent page contains a listing of available modules. AngleThe commons-numbers-angle module provides utilities related to the concept of angle (angle API). The Angle.Deg a = Angle.Turn.of(0.5).toDeg(); Angle.Rad b = a.toRad(); Angle.Turn c = b.toTurn(); // c.getAsDouble() == 0.5 A normalizer can be used to map any value to the natural interval of the angle unit around a provided lower bound, for example // Range: [-180, 180) double angle = Angle.Deg.normalizer(-180).applyAsDouble(270); // angle == -90.0 The normalizer makes use of the Reduce reduce = new Reduce(0, 24); double hours1 = reduce.applyAsDouble(173.5); double hours2 = reduce.applyAsDouble(23.5); double hours3 = reduce.applyAsDouble(-10); // hours1 == 5.5 // hours2 == 23.5 // hours3 == 14.0 The The \( \cos\theta = \frac{\mathbf{a}\cdot\mathbf{b}}{ |\mathbf{a}| |\mathbf{b}| } \) The computation uses extended precision methods to increase the overall accuracy of the result at the cost of a moderate increase in the number of computations. double[] v1 = {1, 0}; double[] v2 = {0, 1}; double[] v3 = {7, 7}; double cosAngle1 = CosAngle.value(v1, v1); double cosAngle2 = CosAngle.value(v1, v2); double cosAngle3 = CosAngle.value(v1, v3); // cosAngle1 == 1 // cosAngle2 == 0 // cosAngle3 == 0.7071067811865476 (sqrt(2) / 2) // Math.toDegrees(Math.acos(cosAngle3)) == 45 ArraysThe commons-numbers-arrays module provides array utilities (arrays API). The double[] x = {3, 1, 2}; double[] y = {1, 2, 3}; double[] z = {0, 5, 7}; SortInPlace.ASCENDING.apply(x, y, z); // x == [1, 2, 3] // y == [2, 3, 1] // z == [5, 7, 0] The MultidimensionalCounter c = MultidimensionalCounter.of(100, 50); int size = c.getSize(); // size == 5000 int index = 233; int[] indices1 = c.toMulti(index); int[] indices2 = c.toMulti(index + 1); // indices1 = [4, 33] : 4 * 50 + 33 == 233 // indices2 = [4, 34] : 4 * 50 + 34 == 234 int index1 = c.toUni(4, 33); // varargs int index2 = c.toUni(indices1); // index == index1 == index2 c.toMulti(49) // [ 0, 49] c.toMulti(50) // [ 1, 0] c.toMulti(4999) // [99, 49] CombinatoricsThe commons-numbers-combinatorics module provides combinatorics utilities such as factorial and binomial coefficients (combinatorics API). The binomial coefficient \( \binom{n}{k} \) can be evaluated as a long bc1 = BinomialCoefficient.value(63, 33); double bc2 = BinomialCoefficientDouble.value(1029, 514); double bc3 = LogBinomialCoefficient.value(152635712, 125636); // bc1 == 7219428434016265740 // bc2 ~ 1.429820686498904e308 // bc3 ~ 1017897.199659759 The factorial \( n! \) can be evaluated as a long f1 = Factorial.value(15); double f2 = Factorial.doubleValue(170); double f3 = LogFactorial.create().value(Integer.MAX_VALUE); // f1 == 1307674368000 // f2 == 7.257415615307999e306 // f3 == 4.3996705655378525e10 Note that if the binomial coefficient or factorial cannot be represented the methods will throw an The LogFactorial lf = LogFactorial.create().withCache(50); Values outside the cache are computed using The combinations defined by the binomial coefficient \( \binom{n}{k} \) can be iterated using the Combinations.of(4, 2).iterator().forEachRemaining(c -> System.out.println(Arrays.toString(c))); Outputs: [0, 1] [0, 2] [1, 2] [0, 3] [1, 3] [2, 3] The lexigraphical order is based on the values in the input array in reverse order. This ordering can be imposed on arbitrary sets using the List<int[]> list = Arrays.asList(new int[][] { {3, 4, 5}, {3, 1, 5}, {3, 2, 5}, {4, 2, 4}, }); list.sort(Combinations.of(6, 3).comparator()); list.forEach(c -> System.out.println(Arrays.toString(c))); Outputs: [4, 2, 4] [3, 1, 5] [3, 2, 5] [3, 4, 5] The Stirling.stirlingS2(3, 3) // 1 : {{1}, {2}, {3}} Stirling.stirlingS2(3, 2) // 3 : {{1, 2}, {3}}, {{1, 3}, {2}} and {{1}, {2, 3}} Stirling.stirlingS2(3, 1) // 1 : {{1, 2, 3}} The evaluation is limited by the ComplexThe commons-numbers-complex module provides utilities for working with complex numbers (complex API). The The double x = 3; double y = 4; Complex c1 = Complex.ofCartesian(x, y); // c1 == x + iy // Convert from polar coordinates double rho = 1.23; double theta = Math.PI / 2; Complex c2 = Complex.ofPolar(rho, theta); Arithmetic operations, elementary functions and trigonometric functions are provided that return new instances of Complex c1 = Complex.ofCartesian(3, 4); Complex c2 = Complex.ofCartesian(5, 6); Complex c3 = c1.multiply(c2).sqrt(); double magnitude = c3.abs(); double argument = c3.arg(); boolean finite = c3.isFinite(); CoreThe commons-numbers-core module provides basic utilities (core API). The classes within this module provide core functionality reused within The interfaces The The double x = Norm.EUCLIDEAN.of(3, -4); // 5 double y = Norm.MANHATTAN.of(3, -4, 5); // 12 double z = Norm.MAXIMUM.of(new double[]{3, -4, 5, -6, -7, -8}); // 8 double big = Double.MAX_VALUE * 0.5; double length = Norm.EUCLIDEAN.of(big, big, big); // length == Math.sqrt(0.5 * 0.5 * 3) * Double.MAX_VALUE The double sum1 = Sum.create().add(1) .addProduct(3, 4) .getAsDouble(); double sum2 = Sum.of(1).addProduct(3, 4) .getAsDouble(); double sum3 = Sum.ofProducts(new double[] {3, 4}, new double[] {5, 6}) .getAsDouble(); // sum1 == sum2 == 13.0 // sum3 == 3 * 5 + 4 * 6 Sum.of(1, 2, Double.NaN).getAsDouble() // NaN Sum.of(1, 2, Double.NEGATIVE_INFINITY).getAsDouble() // -inf The implementation provides up to a 106 bit floating point significand. However the significand is split into two double x1 = 1e100 + 1 - 2 - 1e100; double x2 = Sum.of(1e100, 1, -2, -1e100).getAsDouble(); // x1 == 0.0 // x2 == -1.0 Note that the first part of the sum is maintained as the IEEE754 result. The If the terms to be subtracted are known then the summation can be split into the positive and negative terms, summed in two parts and the result computed by a final subtraction of the double x1 = 1e100 + 1 - 2 - 1e100; Sum s1 = Sum.of(1e100, 1); Sum s2 = Sum.of(2, 1e100); double x2 = s1.subtract(s2).getAsDouble(); // x1 == 0.0 // x2 == -1.0 The class can be used to:
PrecisionThe \( \frac{|a - b|}{\operatorname{max}(|a|, |b|)} \le \epsilon \) Comparisons using the ULP argument specifies the allowed distance between two numbers. Numbers are equal if they have Note: The default implementation for equality allows no numbers between // Default allows no numbers between Precision.equals(1000.0, 1000.0) // true Precision.equals(1000.0, 1000.0 + Math.ulp(1000.0)) // true Precision.equals(1000.0, 1000.0 + 2 * Math.ulp(1000.0)) // false // Absolute - tolerance is floating-point Precision.equals(1000.0, 1001.0) // false Precision.equals(1000.0, 1001.0, 1.0) // true Precision.equals(1000.0, 1000.0 + Math.ulp(1000.0), 0.0) // true (but not binary equal) // ULP - tolerance is integer Precision.equals(1000.0, 1001.0) // false Precision.equals(1000.0, 1001.0, 1) // false Precision.equals(1000.0, 1000.0 + 2 * Math.ulp(1000.0), 1) // false Precision.equals(1000.0, 1000.0 + 2 * Math.ulp(1000.0), 2) // true (n - 1) numbers between Precision.equals(1000.0, 1000.0 + 3 * Math.ulp(1000.0), 2) // false // Relative Precision.equalsWithRelativeTolerance(1000.0, 1001.0, 1e-6) // false Precision.equalsWithRelativeTolerance(1000.0, 1001.0, 1e-3) // true Equality using Precision.equals(Double.NaN, 1000.0) // false Precision.equals(Double.NaN, Double.NaN) // false Precision.equalsIncludingNaN(Double.NaN, Double.NaN) // true Precision.equals(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY) // true Precision.equals(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY) // true Precision.equals(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY) // false
Precision.compareTo(100, 100, 0.0) // 0 Precision.compareTo(100, 101, 1.0) // 0 Precision.compareTo(100, 102, 1.0) // -1 Precision.compareTo(102, 100, 1.0) // 1 The comparison uses the natural ordering and is symmetric with regard to Precision.DoubleEquivalence eq = Precision.doubleEquivalenceOfEpsilon(1.0); eq.lt(100, 100) // false eq.lte(100, 100) // true eq.eq(100, 100) // true eq.gte(100, 100) // true eq.gt(100, 100) // false
// Round to a number of digits to the right of the decimal point Precision.round(678.125, 4) // 678.125 Precision.round(678.125, 3) // 678.125 Precision.round(678.125, 2) // 678.13 Precision.round(678.125, 1) // 678.1 Precision.round(678.125, 0) // 678.0 Precision.round(678.125, -1) // 680.0 Precision.round(678.125, -2) // 700.0 Precision.representableDelta(1.0, 0.1) // 0.10000000000000009 DD: double-doubleThe |x| > |xx| x == x + xx The implementation assumes a normalized representation during operations on a The number \( (x, xx) \) may also be referred to using the labels high and low to indicate the magnitude of the parts as \( ( x_{hi}, x_{lo} ) \), or using a numerical suffix for the parts as \( ( x_0, x_1 ) \). The numerical suffix is typically used when the extended floating-point number has an arbitrary number of parts, for example a quad-double is \( ( x_0, x_1, x_2, x_3 ) \). The parts of the The double x = Math.PI; int y = 42; long z = -8564728970587006436L; DD.of(x).doubleValue() // = x DD.of(y).intValue() // = y DD.of(z).longValue() // = z // (long) (double) z != z The double a = 1.2345678901234567; double b = 123.45678901234567; DD w = DD.ofProduct(a, b); // (152.41578753238835,-1.0325951435749745E-14) DD x = DD.ofSum(a, b); // (124.69135690246912,-1.1102230246251565E-15) DD y = DD.ofDifference(a, b); // (-122.22222112222221,-1.1102230246251565E-15) DD z = DD.fromQuotient(1, 3); // (0.3333333333333333,1.850371707708594E-17) // w.hi() = a * b // x.hi() = a + b // y.hi() = a - b // z.hi() = 1.0 / 3 // Inefficient DD zz = DD.of(1).divide(DD.of(3)); z.equals(zz) // true The BigDecimal pi = new BigDecimal("3.14159265358979323846264338327950288419716939937510"); DD x = DD.from(pi); // (3.141592653589793,1.2246467991473532E-16) pi.compareTo(x.bigDecimalValue()) // != 0 // x.hi() = Math.PI // x.lo() = pi.subtract(new BigDecimal(Math.PI)).doubleValue() DD nan = DD.of(Double.NaN); nan.isFinite() // false nan.bigDecimalValue() // throws NumberFormatException Note: It is not possible to directly specify the two parts of the The long x = -8564728970587006436L; DD.ONE.add(x).longValue() // != x + 1 DD.ONE.add(DD.of(x)).longValue() // == x + 1 The arithmetic methods are not intended to provide an exactly rounded result to 106-bit precision. A compromise has been made between accuracy and performance so that the The following demonstrates a simple sum where the 1.0 / 2 + 1.0 / 3 + 1.0 / 6 // = 0.9999999999999999 DD z = DD.fromQuotient(1, 2) .add(DD.fromQuotient(1, 3)) .add(DD.fromQuotient(1, 6)); // (1.0,-4.622231866529366E-33) z.doubleValue() // = 1.0 Note that the error on the final result is influenced by the calculation. For summation of terms of the same sign a very large number of operations would be required to observe a 1 ULP error in the final double a = 1; double b = Math.pow(2, 53); double c = Math.pow(2, 106); DD.of(a).add(b).add(c).subtract(c).subtract(b) // (0, 0) // NOT (1, 0) When using products the compound error will accumulate faster but is not influenced by the sign of the operands. A power function The Overflow and underflowA double-double number is limited to the same finite range as a This implementation does not support IEEE standards for handling infinite and NaN when used in arithmetic operations. Computations may split a 64-bit Operations that involve splitting a double (multiply, divide) are safe when the base 2 exponent is below 996. This puts an upper limit of approximately +/-6.7e299 on any values to be split; in practice the arguments to multiply and divide operations are further constrained by the expected finite value of the product or quotient. Likewise the smallest value that can be represented is \( 2^{-1074} \). The full 106-bit accuracy will be lost when intermediates are within \( 2^{53} \) of the minimum normalized The double a = 1.5 * Math.pow(2, 1023); double b = 4 * Math.pow(2, -1022); DD x = DD.of(a); DD y = DD.of(b); // Values too extreme for DD arithmetic! x.multiply(y).isFinite() // false // Create fractional representation as [0.5, 1) * 2^b int[] xb = {0}; int[] yb = {0}; x = x.frexp(xb); // (0.75, 0) * 2^1024 y = y.frexp(yb); // (0.5, 0) * 2^-1019 DD z = x.multiply(y); // (0.375, 0) // Rescale by 2^5 z.scalb(xb[0] + yb[0]).doubleValue() // = a * b This simple example shows the added complexity in avoiding under and overflow. Some common operations have been implemented in the Comparison to Math.fmaThe fused multiply-add method The Math.fma(Double.MAX_VALUE, 2.0, -Double.MAX_VALUE) // = Double.MAX_VALUE Math.fma(Double.MIN_VALUE, 0.5, Double.MIN_VALUE) // = Double.MIN_VALUE * 1.5 The round-off from a standard floating-point expression double x = ... double y = ... DD z = DD.ofProduct(x, y); z.hi() // = x * y; z.lo() // = Math.fma(x, y, -x * y) This optimisation is not available on Java 8. The Comparison to IEEE 754 quadrupleA Application of DD
FieldThe commons-numbers-field module provides utilities related to the concept of field (field API). A field is any set of elements that satisfies the field axioms for both addition and multiplication and is a commutative division algebra. The Field<FP64> field = FP64Field.get(); FP64 result = field.one().multiply(3).divide(field.one().multiply(4)); double value = result.doubleValue(); // value = 0.75 The field abstraction can be used to program computations independently of the underlying representation as any FractionThe commons-numbers-fraction module provides fraction utilities (fraction API). Classes are provided to represent rational numbers and to evaluate continued fractions. Rational NumbersThe Instances are constructed with factory methods: int p = 3; int q = 4; Fraction f = Fraction.of(p, q); // f == 3 / 4
int maxIterations = 100; // tolerance Fraction a = Fraction.from(0.6152, 0.02, maxIterations); Fraction b = Fraction.from(0.6152, 1.0e-7, maxIterations); // a = 3 / 5 == 0.6 // b = 769 / 1250 == 0.6152 (exact) // max denominator Fraction c = Fraction.from(0.6152, 9); Fraction d = Fraction.from(0.6152, 9999); // c = 3 / 5 == 0.6 // d = 769 / 1250 == 0.6152 (exact) Fraction e = Fraction.from(Math.pow(2, 31)); // e = Integer.MIN_VALUE / -1 // *** Throws an ArithmeticException *** Fraction.from(Math.pow(2, 32)); The fraction is represented in reduced form using the greatest common divisor. For example Fraction f1 = Fraction.of(-240, 256); Fraction f2 = Fraction.of(15, -16); f1.signum() == -1 f1.equals(f2) == true f1.compareTo(f2) == 0 f1.compareTo(Fraction.ZERO) == -1 Fraction.of(Integer.MIN_VALUE, Integer.MIN_VALUE).compareTo(Fraction.ONE) == 0 Arithmetic operations are provided that return new instances of Fraction result = Fraction.of(1, 2).add(Fraction.of(1, 3)) .add(Fraction.of(1, 6)); // result == 1 / 1 // Note: 1.0 / 2 + 1.0 / 3 + 1.0 / 6 == 0.9999999999999999 (inexact)
double a = Fraction.of(1, 8).doubleValue(); double b = Fraction.of(1, 3).doubleValue(); int c = Fraction.of(8, 3).intValue(); // a == 0.125 (exact) // b == 1.0 / 3 (inexact) // c == 2 (inexact, whole number part of 2 2/3)
The The
BigFraction a = BigFraction.of(1, 3); // a == 1 / 3 The BigFraction a = BigFraction.from(1.0 / 3); // a == 6004799503160661 / 18014398509481984 // max denominator BigFraction b = BigFraction.from(1.0 / 3, 3); // b == 1 / 3 Continued FractionsA generalized continued fraction is an expression of the form: \( x = b_0 + \cfrac{a_1}{b_1 + \cfrac{a_2}{b_2 + \cfrac{a_3}{b_3 + \cfrac{a_4}{b_4 + \ddots\,}}}} \) Classes are provided to evaluate the expression through iteration to a provided error tolerance. The user must supply the coefficients \( a \) and \( b \). The \( \tan(z) = \cfrac{z}{1 - \cfrac{z^2}{3 - \cfrac{z^2}{5 - \ddots\,}}} \) Can be computed using: ContinuedFraction cf = new ContinuedFraction() { @Override public double getA(int n, double x) { return n < 2 ? x : -x * x; } @Override public double getB(int n, double x) { return n == 0 ? 0 : 2 * n - 1; } }; double eps = 1e-8; double z = 0.125; double result = cf.evaluate(z, eps); // result ~ Math.tan(z) The For example the golden ratio: \( x = 1 + \cfrac{1}{1 + \cfrac{1}{1 + \cfrac{1}{1 + \ddots\,}}} \) Can be computed as: double eps = 1e-10; double gr1 = GeneralizedContinuedFraction.value(() -> Coefficient.of(1, 1), eps); double gr2 = GeneralizedContinuedFraction.value(1, () -> Coefficient.of(1, 1), eps); // gr1 ~ gr2 ~ 1.6180339887498948... Whether to separate the term \( b_0 \) depends on the fraction and the algorithm convergence. See the GeneralizedContinuedFraction documentation for details. Note that it is also possible to evaluate part of the fraction using only later terms and then computing the final result by including the early terms. An example using a recursive generator for the evaluation of \( \tan(z) \) is computed using: static class Tan implements Supplier<Coefficient> { private double a; private double b = -1; /** * @param z Argument z */ Tan(double z) { a = z; } @Override public Coefficient get() { b += 2; // Special first case if (b == 1) { double z = a; // Update the term for the rest of the fraction. // The continuant is subtracted from the b terms, thus all the // remaining a terms are negative. a *= -z; return Coefficient.of(z, b); } return Coefficient.of(a, b); } } double z = 0.125; double tan1 = GeneralizedContinuedFraction.value(0, new Tan(z)); // Advance 1 term Tan t = new Tan(z); Coefficient c = t.get(); double tan2 = c.getA() / GeneralizedContinuedFraction.value(c.getB(), t); // tan1 ~ Math.tan(z) // tan2 == Math.tan(z) (more accurate) A simple continued fraction will have an \( a \) coefficient of 1. For example the following fraction: \( \frac{415}{93} = 4 + \cfrac{1}{2 + \cfrac{1}{6 + \cfrac{1}{7}}} \) can be evaluated as a simple continued fraction using: private static Supplier<Coefficient> simpleContinuedFraction(double... coefficients) { return new Supplier<Coefficient>() { /* iteration. */ private int n; /* denominator terms. */ private double[] b = coefficients.clone(); @Override public Coefficient get() { if (n != b.length) { // Return the next term return Coefficient.of(1, b[n++]); } return Coefficient.of(0, 1); } }; } double result1 = GeneralizedContinuedFraction.value(simpleContinuedFraction(4, 2, 6, 7)); double result2 = GeneralizedContinuedFraction.value(4, simpleContinuedFraction(2, 6, 7)); // result1 ~ result2 ~ 415.0 / 93.0 GammaThe commons-numbers-gamma module provides utilities related to the "Gamma" function (gamma API).
Functions are provided using static class methods. These may be optionally parameterized if the method uses an iterative computation to control the function evaluation. For example: double result = Erfc.value(1.23); // Default function evaluation double a = 1.23; double x = 4.56; double result1 = IncompleteGamma.Lower.value(a, x); // Parameterize function evaluation double epsilon = 1e-10; int maxIterations = 1000; double result2 = IncompleteGamma.Lower.value(a, x, epsilon, maxIterations); // result1 ~ result2 The gamma functions are used to evaluate many of the probability distributions provided in the commons-statistics project. PrimesThe commons-numbers-primes module provides utilities related to prime numbers (primes API). The int n = 51237173; boolean prime = Primes.isPrime(n); int m = Primes.nextPrime(n); // prime == false // m == 51237233 List<Integer> f1 = Primes.primeFactors(n); List<Integer> f2 = Primes.primeFactors(m); // f1 == [13, 863, 4567] // f2 == [51237233] // n == 13 * 863 * 4567 QuaternionThe commons-numbers-quaternion module provides utilities for working with quarternion numbers (quaternion API). The The class is immutable and instances are constructed with factory methods. Getters are provided for access to the components: double w = 2; double x = 3; double y = 4; double z = 5; Quaternion h1 = Quaternion.of(w, x, y, z); Quaternion h2 = Quaternion.of(w, new double[]{x, y, z}); h1.getW(); // w h1.getScalarPart(); // w h1.getVectorPart(); // [x, y, z] // h1 == h2 Methods are provided for arithmetic (add, subtract, multiply) and other quaternion operations such as scaling, dot product, negation, conjugation and normalization. Quaternion h = Quaternion.of(1, 2, 3, 4); Quaternion h1 = h.add(Quaternion.ONE); // [2, 2, 3, 4] Quaternion hi = h.add(Quaternion.I); // [1, 3, 3, 4] Quaternion hj = h.add(Quaternion.J); // [1, 2, 4, 4] Quaternion hk = h.add(Quaternion.K); // [1, 2, 3, 5] The binary operations acting on two Quaternion h1 = Quaternion.of(1, 2, 3, 4); Quaternion h2 = Quaternion.of(5, 6, 7, 8); Quaternion result1 = h1.multiply(h2); Quaternion result2 = Quaternion.multiply(h1, h2); // result1 == result2 The class evaluates binary equality using Quaternion q1 = Quaternion.of(1, 2, 3, 4); Quaternion q2 = Quaternion.of(1, 2, 3, 4 + 1e-10); q1.equals(q2); // false q1.equals(q2, 1e-9); // true Quaternions are used to apply rotations in 3-dimensional Euclidean space in the commons-geometry project. The static Quaternion createZRotation(final double theta) { double halfAngle = theta * 0.5; return Quaternion.of(Math.cos(halfAngle), 0, 0, Math.sin(halfAngle)); } Quaternion q1 = createZRotation(0.75 * Math.PI); Quaternion q2 = createZRotation(0.76 * Math.PI); Slerp slerp = new Slerp(q1, q2); slerp.apply(0.0) // ~ q1 slerp.apply(0.25) // ~ createZRotation(0.7525 * Math.PI) slerp.apply(0.5) // ~ createZRotation(0.755 * Math.PI) slerp.apply(0.75) // ~ createZRotation(0.7575 * Math.PI) slerp.apply(1.0) // ~ q2 Root FinderThe commons-numbers-rootfinder module provides utilities for finding the zero of a function (rootfinder API). The double relAccuracy = 1e-6; double absAccuracy = 1e-14; double functionAccuracy = 1e-15; BrentSolver solver = new BrentSolver(relAccuracy, absAccuracy, functionAccuracy); double result1 = solver.findRoot(Math::sin, 3, 4); double result2 = solver.findRoot(Math::sin, 3, 3.14, 4); // With initial guess // result1 ~ result2 ~ Math.PI // *** Throws an IllegalArgumentException *** solver.findRoot(Math::sin, 2, 3); DependenciesApache Commons Numbers requires JDK 1.8+ and has no runtime dependencies. |