blob: 3814faa13ec922bf0b6d9640c35e1d9d4d9667ba [file] [log] [blame]
~~
~~ Licensed to the Apache Software Foundation (ASF) under one or more
~~ contributor license agreements. See the NOTICE file distributed with
~~ this work for additional information regarding copyright ownership.
~~ The ASF licenses this file to You under the Apache License, Version 2.0
~~ (the "License"); you may not use this file except in compliance with
~~ the License. You may obtain a copy of the License at
~~
~~ http://www.apache.org/licenses/LICENSE-2.0
~~
~~ Unless required by applicable law or agreed to in writing, software
~~ distributed under the License is distributed on an "AS IS" BASIS,
~~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~~ See the License for the specific language governing permissions and
~~ limitations under the License.
~~
The Apache Commons Numbers User Guide
* Table of contents
* {{{Overview}Overview}}
* {{{Examples_Modules}Examples Modules}}
* {{{Angle}Angle}}
* {{{Arrays}Arrays}}
* {{{Combinatorics}Combinatorics}}
* {{{Complex}Complex}}
* {{{Core}Core}}
* {{{Precision}Precision}}
* {{{DD:_double-double}DD: double-double}}
* {{{Field}Field}}
* {{{Fraction}Fraction}}
* {{{Rational_Numbers}Rational Numbers}}
* {{{Continued_Fractions}Continued Fractions}}
* {{{Gamma}Gamma}}
* {{{Primes}Primes}}
* {{{Quaternion}Quaternion}}
* {{{Root_Finder}Root Finder}}
* {{{Dependencies}Dependencies}}
Overview
<<<Apache Commons Numbers>>> provides number types and utilities.
The code originated in the {{{https://commons.apache.org/proper/commons-math/}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:
* {{{../commons-numbers-angle/index.html}commons-numbers-angle}} - Utilities related to the concept of angle.
* {{{../commons-numbers-arrays/index.html}commons-numbers-arrays}} - Array utilities.
* {{{../commons-numbers-combinatorics/index.html}commons-numbers-combinatorics}} - Combinatorics utilities such as factorial and binomial coefficients.
* {{{../commons-numbers-complex/index.html}commons-numbers-complex}} - Utilities for working with complex numbers.
* {{{../commons-numbers-core/index.html}commons-numbers-core}} - Basic utilities.
* {{{../commons-numbers-field/index.html}commons-numbers-field}} - Utilities related to the concept of field.
* {{{../commons-numbers-fraction/index.html}commons-numbers-fraction}} - Utilities related to fractions such as rational numbers and continued fractions.
* {{{../commons-numbers-gamma/index.html}commons-numbers-gamma}} - Utilities related to the "Gamma" function.
* {{{../commons-numbers-primes/index.html}commons-numbers-primes}} - Utilities related to prime numbers.
* {{{../commons-numbers-quaternion/index.html}commons-numbers-quaternion}} - Utilities for working with quarternion numbers.
* {{{../commons-numbers-rootfinder/index.html}commons-numbers-rootfinder}} - Utilities for finding the zero of a function.
[]
The {{{../commons-numbers-bom/index.html}commons-numbers-bom}} artifact provides a
Bill of Materials (BOM) to aid in dependency management of the modules.
* Examples Modules
In addition to the modules above, the Commons Numbers
{{{https://commons.apache.org/numbers/download_numbers.cgi}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
{{{../commons-numbers-examples/modules.html}example module parent page}}
contains a listing of available modules.
Angle
The {{{../commons-numbers-angle/index.html}commons-numbers-angle}} module
provides utilities related to the concept of angle
({{{../commons-numbers-angle/apidocs/org/apache/commons/numbers/angle/package-summary.html}angle API}}).
The <<<Angle>>> class can be used to convert angles between common units. Sub-classes are used
to represent the angle units of degrees, radians and turn.
+------------------------------------------+
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 <<<[lo, lo + 360)>>> for degrees:
+------------------------------------------+
// Range: [-180, 180)
double angle = Angle.Deg.normalizer(-180).applyAsDouble(270);
// angle == -90.0
+------------------------------------------+
The normalizer makes use of the <<<Reduce>>> class which can be applied to any interval:
+------------------------------------------+
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 <<<Angle>>> class is used extensively in the
{{{https://commons.apache.org/proper/commons-geometry/}commons-geometry}} project.
The <<<CosAngle>>> class computes the cosine of the angle between two vectors using the
dot product of two vectors and their magnitudes:
\( \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
+------------------------------------------+
Arrays
The {{{../commons-numbers-arrays/index.html}commons-numbers-arrays}} module
provides array utilities
({{{../commons-numbers-arrays/apidocs/org/apache/commons/numbers/arrays/package-summary.html}arrays API}}).
The <<<SortInPlace>>> class can sort a number of arrays using the order imposed by a specified
array:
+------------------------------------------+
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>>> provides a mapping between a unidimensional storage and a
multidimensional conceptual structure. Note that successive values for the unidimensional
index are used for successive values of the <last> index in the indices of the multidimensional
structure. When the dimension size is reached the values roll-over to the next dimension.
The class ensures a 1-to-1 mapping from any index within the size to a multidimensional position.
+------------------------------------------+
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]
+------------------------------------------+
Combinatorics
The {{{../commons-numbers-combinatorics/index.html}commons-numbers-combinatorics}} module
provides combinatorics utilities such as factorial and binomial coefficients
({{{../commons-numbers-combinatorics/apidocs/org/apache/commons/numbers/combinatorics/package-summary.html}combinatorics API}}).
The binomial coefficient \( \binom\{n\}\{k\} \) can be evaluated as a <<<long>>>, <<<double>>>
or using the natural logarithm.
+------------------------------------------+
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>>>, <<<double>>> or using the natural
logarithm.
+------------------------------------------+
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 <<<ArithmeticException>>> in-place of a <<<long>>> value or return infinity
in-place of a <<<double>>> value. The logarithm methods will always compute a valid result
given the bounds imposed by the <<<int>>> arguments.
The <<<LogFactorial>>> class can be created with a cache size. All values up to this size
are computed upon creation. This functionality can be used when a range of values may be
repeatedly required.
+------------------------------------------+
LogFactorial lf = LogFactorial.create().withCache(50);
+------------------------------------------+
Values outside the cache are computed using <<<LogGamma.value(n + 1.0)>>> from the
{{{Gamma}Gamma}} module; this can be used to avoid the object creation of a single-use
instance of LogFactorial.
The combinations defined by the binomial coefficient \( \binom\{n\}\{k\} \) can be
iterated using the <<<Combinations>>> class:
+------------------------------------------+
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 <<<Comparator\<int[]\>>>> provided by an appropriate
<<<Combination>>>:
+------------------------------------------+
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>>> class can evaluate Stirling numbers of the first kind and second kind.
The Stirling numbers of the first kind \( s(n, k) \) arise in the study of permutations,
particularly counting the permutations of a set according to their number of cycles.
The Stirling number of the second kind \( S(n, k) \) is
the number of ways of partitioning a set of \( n \) elements into \( k \) non-empty subsets.
For example a set of 3 elements may be partitioned into:
+------------------------------------------+
Stirling.stirlingS2(3, 1) // 1 : {{1}, {2}, {3}}
Stirling.stirlingS2(3, 2) // 3 : {{1, 2}, {3}}, {{1, 3}, {2}} and {{1}, {2, 3}}
Stirling.stirlingS2(3, 3) // 1 : {{1, 2, 3}}
+------------------------------------------+
The evaluation is limited by the <<<long>>> datatype and the method will raise an
<<<ArithmeticException>>> if the result cannot be represented.
Complex
The {{{../commons-numbers-complex/index.html}commons-numbers-complex}} module
provides utilities for working with complex numbers
({{{../commons-numbers-complex/apidocs/org/apache/commons/numbers/complex/package-summary.html}complex API}}).
The <<<Complex>>> class is a Cartesian representation of a complex number. The complex number is
expressed in the form \( a + ib \) where \( a \) and \( b \) are real numbers and \( i \)
is the imaginary unit which satisfies the equation \( i^2 = -1 \). For the
complex number \( a + ib \), \( a \) is called the <real part> and
\( b \) is called the <imaginary part>. Arithmetic in this class conforms to the C99
standard for complex numbers defined in
{{{https://www.open-std.org/JTC1/SC22/WG14/www/standards}ISO/IEC 9899}}, Annex G.
The <<<Complex>>> class is immutable. Instances are constructed with factory methods:
+------------------------------------------+
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>>> or primitive data types:
+------------------------------------------+
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();
+------------------------------------------+
Core
The {{{../commons-numbers-core/index.html}commons-numbers-core}} module
provides basic utilities
({{{../commons-numbers-core/apidocs/org/apache/commons/numbers/core/package-summary.html}core API}}).
The classes within this module provide core functionality
reused within <<<Apache Commons Numbers>>> and also other projects such as
{{{https://commons.apache.org/proper/commons-geometry/}commons-geometry}} and
{{{https://commons.apache.org/proper/commons-math/}commons-math}}.
The interfaces <<<Addition>>> and <<<Multiplication>>> provide generic typed definitions of
the arithmetic <add> and <multiply> operations. These are extended by <<<NativeOperators>>>
that adds operators that can be implemented in a more performant way. These interfaces are used
by the {{{Field}Field}} module.
The <<<ArithmeticUtils>>> class provides arithmetic utilities such as integer power, unsigned
divide and remainder functions; greatest common divisor; and least common multiple. These
functions are used by the {{{Fraction}Fraction}} module.
The <<<Norm>>> class provides implementations of
{{{https://en.wikipedia.org/wiki/Norm_(mathematics)}norm}} functions. The implementations
may use extended precision methods to increase the overall accuracy of the result
at the cost of a moderate increase in the number of computations. The Euclidean implementation
handles possible under and overflow of intermediates using scaling.
+------------------------------------------+
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 <<<Sum>>> class provides accurate floating-point sums and linear combinations.
The class uses techniques to mitigate round off errors resulting from
standard floating-point operations, increasing the overall accuracy of
results at the cost of a moderate increase in the number of computations.
The <<<Sum>>> can add numbers and products of numbers.
The result is returned as the high-precision value if it is finite, or the standard IEEE754
result otherwise.
+------------------------------------------+
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>>> values which may be separated by more than <<<2^53>>>
by using the exponent of the second <<<double>>>.
This provides protection against cancellation in situations that would not be handled by an
IEEE754 binary 128 format with a 113 bit significand:
+------------------------------------------+
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 <<<Sum>>>
is therefore not a full <<<double-double>>> implementation, which would maintain the sum
as the current total and a round-off term. This difference makes the <<<Sum>>> class faster
at the cost of some accuracy during addition of terms that cancel.
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 <<<Sum>>> of negative parts.
+------------------------------------------+
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:
* Provide accurate summation of numbers with the same sign irrespective of input order;
* Reduce cancellation effects that occur when large magnitude numbers
with opposite signs are summed together with relatively small values;
* Compute using two sums the terms of the same sign and the final result by combining
the sums (using add or subtract).
[]
* Precision
The <<<Precision>>> class provides comparison of floating-point numbers using relative, absolute
and unit of least precision ({{{https://en.wikipedia.org/wiki/Unit_in_the_last_place}ULP}})
tolerances. Comparison using the relative tolerance \( \epsilon \) is symmetric as the relative
delta is computed using the largest magnitude of the input pair of numbers:
\( \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 <<<(ulp - 1)>>> representable numbers or fewer <between> <<<a>>>
and <<<b>>>. Use <<<ulp = 0>>> for binary equality.
Note: The default implementation for equality allows no numbers <between> <<<a>>> and <<<b>>>.
It is equivalent to <<<Precision.equals(a, b, 1)>>>. Thus using a floating-point delta of
<<<0.0>>> may indicate numbers are equal when they are not <binary> equal (see example below).
+------------------------------------------+
// 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 <<<NaN>>> values will be <<<false>>>. To allow two <<<NaN>>> values to be
equal requires the use of the method <<<equalsIncludingNaN>>>. Special handling of <<<NaN>>>
values allows the default implementation to be optimized for the typical use case comparing
finite numbers. Note that infinity values are equal.
+------------------------------------------+
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>>> provides a <<<compareTo>>> method to provide ordering of numbers that are
not considered equal using the tolerance:
+------------------------------------------+
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 <<<NaN>>> values.
The comparison using <<<\<, ==, \>>>> is extended in the <<<DoubleEquivalence>>> interface
that supports <<<\<=, \>=>>> and signum.
+------------------------------------------+
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
+------------------------------------------+
<<<Precision>>> also provides methods for other floating-point operations such as rounding and
computing a representable delta from a number and an ideal delta.
+------------------------------------------+
// 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-double
The <<<DD>>> class provides an extended precision floating-point number.
A double-double is an unevaluated sum of two IEEE <<<double>>> precision numbers capable of
representing at least 106 bits of significand. A normalized double-double number \( (x, xx) \)
satisfies the condition that the parts are non-overlapping in magnitude such that:
+------------------------------------------+
|x| > |xx|
x == x + xx
+------------------------------------------+
The implementation assumes a normalized representation during operations on a <<<DD>>>
number and computes results as a normalized representation. The number is limited to the
same exponent range as a <<<double>>>. Thus the number can be considered
as a standard IEEE <<<double>>> with additional information that would be lost to rounding.
This information can be used in arithmetic operations so that compound calculation can
reduce the error present in the final result returned as a <<<double>>>.
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 <<<DD>>> can be accessed using the <<<hi()>>>
and <<<lo()>>> methods and the evaluated sum \( x + xx \) as <<<doubleValue()>>>.
The <<<DD>>> class is immutable. Instances are constructed with factory methods.
A <<<DD>>> can be constructed from a <<<double>>>, <<<int>>> or <<<long>>> primitive. In the
case of a <<<long>>> this maintains the full 64-bits of information; this is not possible
when using implicit type conversion to a <<<double>>>. These conversions can be reversed
as the <<<DD>>> provides type conversions using the <<<java.lang.Number>>> methods.
+------------------------------------------+
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 <<<DD>>> class can be created as the result of a <<<double>>> operation and the round-off
error. In the case of addition and multiplication the result is exact. For division the result
will have the closest 106-bit representation to the exact result.
Note that use of the factory constructors for <<<double>>> arithmetic is preferred over
constructing the arguments as a <<<DD>>> from a <<<double>>> and performing the equivalent
operation in <<<DD>>> arithmetic:
+------------------------------------------+
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 <<<DD>>> can also be converted from and to a <<<BigDecimal>>>. The conversion <<from>> may
lose precision. The conversion <<to>> is exact but only supported for finite numbers as BigDecimal
does not support infinity and NaN. The method <<<isFinite()>>> can be used to verify that the
evaluated sum \( x + xx \) is finite; this is only true when both parts are finite and conversion
to <<<BigDecimal>>> is possible. Note that <<<BigDecimal>>> can be used for numerical equality
and ranking operations as the <<<DD>>> class does not support <<<java.lang.Comparable>>>, and
the <<<equals(Object)>>> method is true for <<binary>> equality of the parts, not <<numerical>>
equality of their evaluated sum.
The following demonstrates a round trip of \( \pi \) to 50 decimal places. The <<<DD>>> is
limited to approximately 34 decimal places and this is split into
the <<<double>>> value for \( \pi \) and a <<<double>>> representing the rounding error.
+------------------------------------------+
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 <<<DD>>> number.
The two parts must be added using a sum to ensure the <<<DD>>> maintains a normalized
representation. If the two parts already represent a number
\( (x, xx) \) such that \( x == x + xx \) then the magnitudes of the parts will be
unchanged; any signed zeros may be subject to a sign change.
The <<<DD>>> class provides the arithmetic operations add, subtract, multiply, and divide for a
<<<double>>> or <<<DD>>> argument. <<<int>>> and <<<long>>> arguments can be used as a
<<<double>>> due to implicit type conversion. However if the <<<long>>> value has more than
53-bits of precision then it should first be converted to a <<<DD>>>.
+------------------------------------------+
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 <<<DD>>> class is a viable alternative to using <<<BigDecimal>>> for high accuracy
arithmetic when the ultimate result is required as a <<<double>>>. The approximate error bounds
of operations are supplied in the class javadoc. Typical errors bounds are within a relative error
of 1-4 <eps> of the exact result where <eps> is \( 2^\{-106\} \).
The following demonstrates a simple sum where the <<<double>>> representation of a fraction is
inexact and results in a rounding error. This is removed by extending the fraction to a
double-double representation:
+------------------------------------------+
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>>> result. If terms of the opposite sign are
summed then smaller magnitude intermediate terms can be lost due to the limited 106-bit
precision. In this case almost total cancellation will product the incorrect result.
+------------------------------------------+
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 <<<pow(int)>>> is provided for compound multiplication
of the same argument that is more efficient but does not reduce the error bound.
The <<<DDMath>>> class provides special support for operations using the <<<DD>>> class.
The purpose is to supplement the arithmetic operations in the <<<DD>>> class providing
greater accuracy at the cost of performance.
This includes a power function that returns the result in a fractional representation
to avoid over or underflow, with a lower error bound that the equivalent function in <<<DD>>>.
** Overflow and underflow
A double-double number is limited to the same finite range as a <<<double>>>.
The class is intended for use when the ultimate result is finite and intermediate values
do not approach infinity or zero.
This implementation does not support IEEE standards for handling infinite and NaN when used
in arithmetic operations. Computations may split a 64-bit <<<double>>> into two parts and/or use
subtraction of intermediate terms to compute round-off parts. These operations may generate
infinite values due to overflow which then propagate through further operations to NaN,
for example computing the round-off using <<<Inf - Inf = NaN>>>.
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 <<<double>>> \( 2^\{-1022\} \).
The <<<DD>>> result can be verified by checking it is a finite evaluated sum using
<<<isFinite()>>>. Computations expecting to approach over or underflow must use scaling of
intermediate terms using <<<frexp(int[])>>> and <<<scalb(int)>>> and
appropriate management of the current base 2 scale. The <<<frexp(int[])>>> method creates
a number with a fractional part \( f \) in the range \( [0.5, 1) \) and an exponent part
\( 2^b \) such that \( x = f \times 2^b \). The following example demonstrates scaling and
rescaling:
+------------------------------------------+
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 <<<Sum>>> and <<<Norm>>> classes with
extended precision floating-point arithmetic. These use appropriate scaling and
ensure the correct IEEE result is returned in the event of a non-finite result.
Algorithms include summation, sum-of-products and Euclidean norms.
** Comparison to Math.fma
The fused multiply-add method <<<Math.fma(double, double, double)>>> added in Java 9 returns
the exact product of the first two arguments summed with the third argument and then rounded
once to the nearest <<<double>>>. This avoids the two rounding operations that would occur
using <<<a * b + c>>> as a regular floating-point expression. The result is returned
as a <<<double>>>.
The <<<DD>>> class can represent the exact 106-bit product <<<a * b>>> as \( (x, xx) \).
Unlike <<<Math.fma>>>, which uses effectively unlimited precision arithmetic, the addend
<<<c>>> can only be used if it overlaps either the upper part \( x \) or the lower part
\( xx \) of the number. If too small then it will not change \(x, xx \); if too large then
the final result will be \( (c, x) \).
However the result will be returned with information that can be used in further computation.
Also note that <<<Math.fma>>> will compute the correct IEEE result if the value is non-finite.
It will also be protected from over and underflow for the intermediate result, for example:
+------------------------------------------+
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 <<<x * y>>> can be computed using
FMA:
+------------------------------------------+
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 <<<DD>>> class uses standard <<<double>>>
arithmetic to split the arguments into parts \( x = x_h + x_l \) and \( y = y_h + y_l \),
each of which can be multiplied exactly by <<<double>>> arithmetic and used to compute
the round-off component. Splitting and computation of the round-off takes 16 FLOPS which is
far slower than a hardware supported FMA operation.
** Application of DD
<<<DD>>> arithmetic is slower than <<<double>>> arithmetic and faster than <<<BigDecimal>>>.
The class has been implemented to avoid costly branch conditions in operations, such as those
required to support IEEE arithmetic for non-finite values, and avoid significant extra
computation for a gain of only 1 or 2 ULP accuracy in the lower part of the double-double number.
Users should assess the benefits of using standard <<<double>>> arithmetic, with or without
<<<Math.fma>>>, against <<<DD>>> or <<<BigDecimal>>> arithmetic with suitable accuracy and
performance benchmark data. For example the <<<DD>>> class is used in <<<Commons Numbers>>> and
{{{https://commons.apache.org/proper/commons-statistics/}commons-statistics}}
in targeted parts of function evaluations where accuracy is improved by 8-10 bits over standard
<<<double>>> arithmetic, or even to enable computations that have catastrophic error using
<<<double>>> arithmetic.
Field
The {{{../commons-numbers-field/index.html}commons-numbers-field}} module
provides utilities related to the concept of field
({{{../commons-numbers-field/apidocs/org/apache/commons/numbers/field/package-summary.html}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>>> interface
defines the operations of a field. Implementations are provided for rational numbers
as <<<FractionField>>> and <<<BigFractionField>>>; and real numbers as <<<FP64Field>>>.
+------------------------------------------+
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 <<<Field\<T\>>>> can be manipulated using the arithmetic operations of
add, subtract, multiply and divide.
Fraction
The {{{../commons-numbers-fraction/index.html}commons-numbers-fraction}} module
provides fraction utilities
({{{../commons-numbers-fraction/apidocs/org/apache/commons/numbers/fraction/package-summary.html}fraction API}}).
Classes are provided to represent rational numbers and to evaluate continued fractions.
* Rational Numbers
The <<<Fraction>>> class is a representation of a rational number <<<p / q>>> using
<<<int>>> values for the numerator <<<p>>> and denominator <<<q>>>.
Instances are constructed with factory methods:
+------------------------------------------+
int p = 3;
int q = 4;
Fraction f = Fraction.of(p, q);
// f == 3 / 4
+------------------------------------------+
<<<Fraction>>> can be created using a <<<double>>>. The floating-point number may not be exactly
representable; a continued fraction is used to converge on a rational representation within a
specified absolute tolerance, or a maximum denominator. An <<<ArithmeticException>>> is thrown
if the algorithm fails to converge or the number is not representable.
+------------------------------------------+
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
<<<240 / 256>>> is reduced to <<<15 / 16>>>. The sign can be either in the numerator or
the denominator; the sign of the fraction is accessed using the <<<signum()>>> method.
Fraction equality can be evaluated using <<<equals()>>>. The class implements <<<Comparable\<Fraction\>>>>
to allow sorting using the natural order imposed by the fraction's sign and magnitude.
+------------------------------------------+
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>>>. Note that
fraction operations are <exact>.
+------------------------------------------+
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)
+------------------------------------------+
<<<Fraction>>> extends <<<java.lang.Number>>> and can be converted to other primitive numbers
with possible loss of precision:
+------------------------------------------+
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)
+------------------------------------------+
<<<Fraction>>> is limited to rational numbers representable using <<<int>>> values. Operations
that cannot be represented will raise an <<<ArithmeticException>>>. Intermediate
computations may use the <<<long>>> datatype and arithmetic is relatively fast.
The <<<BigFraction>>> class uses <<<BigInteger>>> for the numerator and denominator and can
provide exact arithmetic up to the limitations of <<<BigInteger>>>. This is documented as
at least <<<+/- 2^Integer.MAX_VALUE>>> (exclusive) and may support values outside of that range.
The <<<BigFraction>>> class provides all the arithmetic operations of <<<Fraction>>> and
can be used when <<<Fraction>>> cannot represent the rational numbers; there will be a performance
cost to using <<<BigFraction>>> due to the switch from primitive values to <<<BigInteger>>> for
computations.
<<<BigFraction>>> can be constructed from <<<int>>>, <<<long>>> or <<<BigInteger>>> numerator
and denominators.
+------------------------------------------+
BigFraction a = BigFraction.of(1, 3);
// a == 1 / 3
+------------------------------------------+
The <<<BigFraction>>> conversion of <<<double>>> values can be exact, or adjusted to be
within a provided tolerance. Note that exact conversion may create an unexpected rational
number as it is limited by the precision of the input <<<double>>> value which may be inexact:
+------------------------------------------+
BigFraction a = BigFraction.from(1.0 / 3);
// a == 6004799503160661 / 18014398509481984
// max denominator
BigFraction b = BigFraction.from(1.0 / 3, 3);
// b == 1 / 3
+------------------------------------------+
* Continued Fractions
A 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 <<<ContinuedFraction>>> class requires a function to supply the <n>th coefficients; the
API allows the fraction function to be evaluated for different arguments. This is useful when
the coefficients can be computed using a formula based on the index and the argument.
The class is abstract and must be extended to provide the coefficients \( a \) and \( b \).
For example the following fraction:
\( \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 <<<GeneralizedContinuedFraction>>> class requires a generator for the next pair of
coefficients. This is useful when the coefficients can be computed using the previous values.
The class evaluates the fraction using static methods and a supplied generator of coefficients.
This can be done with the generator supplying the initial term \( b_0 \) where \( a_0 \) is
ignored, or with the generator starting at \( (a_1, b_1) \) and the term \( b_0 \) provided
separately.
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
{{{../commons-numbers-fraction/apidocs/org/apache/commons/numbers/fraction/GeneralizedContinuedFraction.html}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
+------------------------------------------+
Gamma
The {{{../commons-numbers-gamma/index.html}commons-numbers-gamma}} module
provides utilities related to the "Gamma" function
({{{../commons-numbers-gamma/apidocs/org/apache/commons/numbers/gamma/package-summary.html}gamma API}}).
*---+---+
Gamma function | \\( \\Gamma(a) \\)
*---+---+
Incomplete gamma functions (lower and upper) | \\( \\Gamma(a) = \\gamma(a, x) + \\Gamma(a, x) \\)
*---+---+
Regularized gamma functions (lower and upper) | \\( 1 = P(a, x) + Q(a, x) \\)
*---+---+
Ratio of gamma functions | \\( \\frac\\{\\Gamma(a)\\}\\{\\Gamma(b)\\} \\)
*---+---+
Digamma function | \\( \\frac\\{d\\}\\{dx\\}(\\ln \\Gamma(x)) \\)
*---+---+
Trigamma function | \\( \\psi_1(x) = \\frac\\{d^2\\}\\{dx^2\\} (\\ln \\Gamma(x)) \\)
*---+---+
Logarithm of the absolute value of the gamma function | \\( \\ln\\, \\lvert \\Gamma(x) \\rvert \\)
*---+---+
Beta function | \\( B(a, b) = \\frac\\{\\Gamma(a)\\ \\Gamma(b)\\}\\{\\Gamma(a+b)\\} \\)
*---+---+
Incomplete beta function (and the complement) | \\( B_x(a, b) = \\int_0^x t^\\{a-1\\}\\,(1-t)^\\{b-1\\}\\,dt \\)
*---+---+
Logarithm of the beta function | \\( \\ln B(a, b) \\)
*---+---+
Error function | \\( \\operatorname\\{erf\\}(z) \\)
*---+---+
Complementary error function | \\( \\operatorname\\{erfc\\}(z) \\)
*---+---+
Scaled complementary error function | \\( \\operatorname\\{erfcx\\}(z) \\)
*---+---+
Difference between error function values | \\( \\operatorname\\{erf\\}(a) - \\operatorname\\{erf\\}(b) \\)
*---+---+
Inverse error functions |
*---+---+
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
{{{https://commons.apache.org/proper/commons-statistics/}commons-statistics}} project.
Primes
The {{{../commons-numbers-primes/index.html}commons-numbers-primes}} module
provides utilities related to prime numbers
({{{../commons-numbers-primes/apidocs/org/apache/commons/numbers/primes/package-summary.html}primes API}}).
The <<<Primes>>> class provides static methods for working with prime numbers in the range of
an <<<int>>>. Methods are provided to determine if a value is prime, compute the next prime
after a value and the prime factors of a number.
+------------------------------------------+
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
+------------------------------------------+
Quaternion
The {{{../commons-numbers-quaternion/index.html}commons-numbers-quaternion}} module
provides utilities for working with quarternion numbers
({{{../commons-numbers-quaternion/apidocs/org/apache/commons/numbers/quaternion/package-summary.html}quaternion API}}).
The <<<Quaternion>>> class represents Hamilton's hypecomplex number in the form
\( H = w + x\,i + y\,j + z\,k \), where \( w \) is the scalar component and \( [x, y, z] \) is
the vector component.
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>>> instances are provided as instance
methods and static methods for convenience when using method references as lambda functions:
+------------------------------------------+
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 <<<equals(Object)>>> and provides a helper method
to evaluate equality within an absolute tolerance:
+------------------------------------------+
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
{{{https://commons.apache.org/proper/commons-geometry/}commons-geometry}} project.
The <<<Slerp>>> class performs spherical linear interpolation
({{{https://en.wikipedia.org/wiki/Slerp}Slerp}}). The algorithm is designed to interpolate
smoothly between two rotations/orientations, producing a constant-speed motion along an arc.
+------------------------------------------+
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 Finder
The {{{../commons-numbers-rootfinder/index.html}commons-numbers-rootfinder}} module
provides utilities for finding the zero of a function
({{{../commons-numbers-rootfinder/apidocs/org/apache/commons/numbers/rootfinder/package-summary.html}rootfinder API}}).
The <<<BrentSolver>>> class implements the Brent algorithm for finding the zeros of real
univariate functions. The solver requires an interval that brackets a root and will raise an
exception if there is no sign change between the bounds \( [a, b] \). The relative \( \epsilon \)
and absolute \( \delta \) accuracy specify the convergence tolerance for the function value
\( x \) to zero as: \( 2\,\epsilon\,|x| + \delta \).
The function accuracy is used to return the initial bracket bounds, or initial guess,
if the function value is within the specified accuracy of zero.
+------------------------------------------+
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);
+------------------------------------------+
Dependencies
Apache Commons Numbers requires JDK 1.8+ and has no runtime dependencies.