Releases · eobermuhlner/big-math (original) (raw)
Release 2.3.2
API changes
BigRational implements now Serializable
The BigRational class implements now the Serializable interface and can be serialized
with the standard Java approach using ObjectInputStream and deserialized using ObjectOutputStream.
BigRational extends now Number
The BigRational class extends now from Number and provides the following standard methods:
int intValue()long longValue()float floatValue()double doubleValue()
Bugfixes
BigRational.toFloat() and BigRational.toDouble() with large nominators/denominators
The methods BigRational.toFloat() and BigRational.toDouble() failed to convert large nominators/denominators
into valid float, respectively double numbers.
For example:
BigRational x = BigRational.valueOf("8.804462619980757911125181749462772084351"); System.out.println("rational : " + x.toRationalString()); System.out.println("float : " + x.toFloat());
would print:
rational : 8804462619980757911125181749462772084351/1000000000000000000000000000000000000000
float : NaN
After the fix this example prints:
rational : 8804462619980757911125181749462772084351/1000000000000000000000000000000000000000
float : 8.804462
BigRational.toIntegerRationalString() with small negative numbers
Negative rational numbers smaller than 1 where printed without - sign.
For example:
BigRational v = valueOf(-1, 2); System.out.println("small negative rational toString(): " + v); System.out.println("small negative rational toIntegerRationalString(): " + v);
would print:
small negative rational toString(): -0.5
small negative rational toIntegerRationalString(): 1/2
After the fix this example prints:
small negative rational toString(): -0.5
small negative rational toIntegerRationalString(): -1/2
BigDecimalMath.root(x, n) faster with large n
The BigDecimalMath.root(BigDecimal, BigDecimal, MathContext) function converged very slowly for larger values of n.
This was due to a bad initial value for the Newton-Raphson approximation.
Now the initial value for the Newton-Raphson approximation is calculated using double precision.
If the initial value cannot be calculated using double precision the function pow(x, 1/n) is used to calculate the root.
Enhancements
No enhancements.
Examples
Note: The example code is available on github, but not part of the big-math library.
No changes in the examples.
Release 2.3.1
IMPORTANT
The big-math release 2.3.1 published on maven central (https://search.maven.org/) was accidentally built with uncommitted experimental changes.
DO NOT USE RELEASE 2.3.1 AND USE 2.3.2 instead.
API changes
BigRational implements now Serializable
The BigRational class implements now the Serializable interface and can be serialized
with the standard Java approach using ObjectInputStream and deserialized using ObjectOutputStream.
BigRational extends now Number
The BigRational class extends now from Number and provides the following standard methods:
int intValue()long longValue()float floatValue()double doubleValue()
Bugfixes
BigRational.toFloat() and BigRational.toDouble() with large nominators/denominators
The methods BigRational.toFloat() and BigRational.toDouble() failed to convert large nominators/denominators
into valid float, respectively double numbers.
For example:
BigRational x = BigRational.valueOf("8.804462619980757911125181749462772084351"); System.out.println("rational : " + x.toRationalString()); System.out.println("float : " + x.toFloat());
would print:
rational : 8804462619980757911125181749462772084351/1000000000000000000000000000000000000000
float : NaN
After the fix this example prints:
rational : 8804462619980757911125181749462772084351/1000000000000000000000000000000000000000
float : 8.804462
BigRational.toIntegerRationalString() with small negative numbers
Negative rational numbers smaller than 1 where printed without - sign.
For example:
BigRational v = valueOf(-1, 2); System.out.println("small negative rational toString(): " + v); System.out.println("small negative rational toIntegerRationalString(): " + v);
would print:
small negative rational toString(): -0.5
small negative rational toIntegerRationalString(): 1/2
After the fix this example prints:
small negative rational toString(): -0.5
small negative rational toIntegerRationalString(): -1/2
BigDecimalMath.root(x, n) faster with large n
The BigDecimalMath.root(BigDecimal, BigDecimal, MathContext) function converged very slowly for larger values of n.
This was due to a bad initial value for the Newton-Raphson approximation.
Now the initial value for the Newton-Raphson approximation is calculated using double precision.
If the initial value cannot be calculated using double precision the function pow(x, 1/n) is used to calculate the root.
Enhancements
No enhancements.
Examples
Note: The example code is available on github, but not part of the big-math library.
No changes in the examples.
Release 2.3.0
API changes
No API changes.
Bugfixes
No Bugfix changes.
Enhancements
Added DefaultBigDecimalMath.createLocalMathContext() and withLocalMathContext()
The class DefaultBigDecimalMath is a wrapper around BigDecimalMath that passes always the current MathContext to the
functions that need a MathContext argument.
The initial default MathContext is equivalent to MathContext.DECIMAL128 but this can be overridden by setting the following system properties:
ch.obermuhlner.math.big.default.precisionto a positive integer precision (default=34)ch.obermuhlner.math.big.default.roundingto a RoundingMode name (default=HALF_UP)
It is also possible to programmatically set the default MathContext using setDefaultMathContext(MathContext).
It is recommended to set the desired precision in the MathContext very early in the startup of the application and to not change it afterwards.
Important: Avoid the pitfall of setting the precision temporarily using setDefaultMathContext(MathContext) for a calculation.
This can lead to race conditions and calculations with the wrong precision if other threads in your application do the same thing.
To set a temporary MathContext you have to choice to use either:
DefaultBigDecimalMath.createLocalMathContext()in a try-with-resources statementDefaultBigDecimalMath.withLocalMathContext()with a lambda function
Example code using DefaultBigDecimalMath.createLocalMathContext():
System.out.println("Pi[default]: " + DefaultBigDecimalMath.pi()); try (DefaultBigDecimalMath.LocalMathContext context = DefaultBigDecimalMath.createLocalMathContext(5)) { System.out.println("Pi[5]: " + DefaultBigDecimalMath.pi()); try (DefaultBigDecimalMath.LocalMathContext context2 = DefaultBigDecimalMath.createLocalMathContext(10)) { System.out.println("Pi[10]: " + DefaultBigDecimalMath.pi()); }; System.out.println("Pi[5]: " + DefaultBigDecimalMath.pi()); }; System.out.println("Pi[default]: " + DefaultBigDecimalMath.pi());
Example code using DefaultBigDecimalMath.withLocalMathContext():
System.out.println("Pi[default]: " + DefaultBigDecimalMath.pi()); DefaultBigDecimalMath.withLocalMathContext(5, () -> { System.out.println("Pi[5]: " + DefaultBigDecimalMath.pi()); DefaultBigDecimalMath.withLocalMathContext(10, () -> { System.out.println("Pi[10]: " + DefaultBigDecimalMath.pi()); }); System.out.println("Pi[5]: " + DefaultBigDecimalMath.pi()); }); System.out.println("Pi[default]: " + DefaultBigDecimalMath.pi());
Both snippets will give the following output:
Pi[default]: 3.141592653589793238462643383279503 Pi[5]: 3.1416 Pi[10]: 3.141592654 Pi[5]: 3.1416 Pi[default]: 3.141592653589793238462643383279503
The temporary MathContext are stored in ThreadLocal variables
and will therefore not conflict with each other when used in multi-threaded use case.
Important: Due to the ThreadLocal variables the temporary MathContext will
not be available in other threads.
This includes streams using parallel(), thread pools and manually started threads.
If you need temporary MathContext for calculations then you must
set the local MathContext inside every separate thread.
try (DefaultBigDecimalMath.LocalMathContext context = DefaultBigDecimalMath.createLocalMathContext(5)) { BigDecimalStream.range(0.0, 1.0, 0.01, DefaultBigDecimalMath.currentMathContext()) .map(b -> DefaultBigDecimalMath.cos(b)) .map(b -> "sequential " + Thread.currentThread().getName() + " [5]: " + b) .forEach(System.out::println);
BigDecimalStream.range(0.0, 1.0, 0.01, DefaultBigDecimalMath.currentMathContext())
.parallel()
.map(b -> {
try (DefaultBigDecimalMath.LocalMathContext context2 = DefaultBigDecimalMath.createLocalMathContext(5)) {
return DefaultBigDecimalMath.cos(b);
}
})
.map(b -> "parallel " + Thread.currentThread().getName() + " [5]: " + b)
.forEach(System.out::println);}
Examples
Note: The example code is available on github, but not part of the big-math library.
Examples for createLocalMathContext() and withLocalMathContext()
Example code was added to the class DefaultBigDecimalMathExample
to demonstrate the usage of DefaultBigDecimalMath.createLocalMathContext()
and DefaultBigDecimalMath.withLocalMathContext().
Release 2.2.1
API changes
No API changes.
Bugfixes
Concurrency bug in Taylor series based calculations
The code that calculates Taylor series caches the intermediate results
to improve the performance of future calculations of the same Taylor series.
This cache had a bug that would lead toNullPointerExceptions or wrong calculation when used in a multi-threaded scenario.
The bug was fixed by synchronizing the access to the cache and other changes to mutable state.
Special thanks to modestukasai for reporting and anlyzing the bug.
Enhancements
No enhancements.
Examples
Note: The example code is available on github, but not part of the big-math library.
Improved performance regression measurements
The PerformanceRegressionBigDecimalMath example class was improved and wrapped in
several gradle projects to allow reproducable performance regression measurements
over all releases of big-math.
Release 2.2.0
API changes
Support for NaN, POSITIVE_INFINITY, NEGATIVE_INFINITY in BigFloat
The BigFloat class supports now the same special values as double:
NaNfor values that cannot be represented a numberPOSITIVE_INFINITYto represent positive infinite valuesNEGATIVE_INFINITYto represent negative infinite values
Bugfixes
No Bugfix changes.
Enhancements
Performance optimizations
Performance analysis of the basic operations on BigDecimal has shown
that the add() and subtract() operation are faster without
specifying a MathContext argument. The multiply() operation has a
more complex performance behaviour. A single multiplication tends to be
faster without MathContext argument but the following operations are
at risk to be slower since it accumulates precision.
Many operations where manually fine tuned to find the optimum
performance.
The following chart shows performance improvements for the involved
operations:
Examples
Note: The example code is available on github, but not part of the big-math library.
No changes in the examples.
Release 2.1.0
API changes
Use DefaultBigDecimalMath to avoid passing MathContext
Due to popular demand a convenience class DefaultBigDecimalMath was added that provides mathematical functions
where the MathContext must not be passed every time.
The class DefaultBigDecimalMath is a wrapper around BigDecimalMath that passes always the same default MathContext to the
functions that need a MathContext argument.
This class is designed for applications that will always need the same precision in all calculations.
The initial default MathContext is equivalent to MathContext.DECIMAL128
but this can be overridden by setting the following system properties:
ch.obermuhlner.math.big.default.precisionto a positive integer precision (default=34)ch.obermuhlner.math.big.default.roundingto aRoundingModename (default=HALF_UP)
It is also possible to set the default MathContext using DefaultBigDecimalMath.setDefaultMathContext(MathContext).
It is recommended to set the desired precision in the MathContext early in the startup of the application.
Important: Avoid the pitfall of setting the precision temporarily for a calculation.
This can lead to race conditions and calculations with the wrong precision
if other threads in your application do the same thing.
Improved rounding with BigDecimalMath.roundWithTrailingZeroes()
The new function BigDecimalMath.roundWithTrailingZeroes() rounds the specified BigDecimal to the precision of the specified MathContext including trailing zeroes.
Example:
MathContext mc = new MathContext(5);
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("1.234567"), mc)); // 1.2346
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("123.4567"), mc)); // 123.46
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("0.001234567"), mc)); // 0.0012346
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("1.23"), mc)); // 1.2300
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("1.230000"), mc)); // 1.2300
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("0.00123"), mc)); // 0.0012300
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("0"), mc)); // 0.0000
System.out.println(BigDecimalMath.roundWithTrailingZeroes(new BigDecimal("0.00000000"), mc)); // 0.0000
For consistency the normal BigDecimal.round() function has also been provided in BigDecimalMath.
Bugfixes
Performance improvement in log()
In release 2.0.0 the calculation precision was improved at the cost of calculation performance.
The calculation performance has now again been improved by up to factor 5 and is practically back to pre-2.0.0 levels,
while the calculations are still correct to the specified precision.
Fix sqrt() sometimes wrong in last digit with low precision.
Calculation of square root with low precision (16 digits and less) could sometimes
calculate the last digit wrong.
For example:
BigDecimalMath.sqrt(new BigDecimal("43.79427225801566", new MathContext(16)));
returns 6.617724099568950 instead of 6.617724099568949
This has been fixed.
Fix BigDecimalMath functions with MathContext.UNLIMITED
The behaviour of the BigDecimalMath functions when being used with the MathContext.UNLIMITED was badly defined.
In many cases the calculation was done with a low precision like 10.
The functions that calculate the result with an algorithm using well defined and obvious operations
may throw the same ArithmeticException as the underlying BigDecimal operations
if the specified MathContext has a precision of 0 (for example MathContext.UNLIMITED):
BigDecimalMath.reciprocal(BigDecimal)BigDecimalMath.bernoulli(int, MathContext)BigDecimalMath.factorial(BigDecimal, MathContext)with integer argumentBigDecimalMath.gamma(BigDecimal, MathContext)with integer argumentBigDecimalMath.pow(BigDecimal, long, MathContext)
All other functions that use approximations to calculate the result will throw a UnsupportedOperationException
if the specified MathContext has a precision of 0 (for example MathContext.UNLIMITED):
BigDecimalMath.factorial(BigDecimal, MathContext)with non-integer argumentBigDecimalMath.gamma(BigDecimal, MathContext)with non-integer argumentBigDecimalMath.pow(BigDecimal, BigDecimal, MathContext)BigDecimalMath.sqrt(BigDecimal, MathContext)BigDecimalMath.root(BigDecimal, BigDecimal, MathContext)BigDecimalMath.log(BigDecimal, MathContext)BigDecimalMath.log2(BigDecimal, MathContext)BigDecimalMath.log10(BigDecimal, MathContext)BigDecimalMath.pi(MathContext)BigDecimalMath.e(MathContext)BigDecimalMath.exp(BigDecimal, MathContext)BigDecimalMath.sin(BigDecimal, MathContext)BigDecimalMath.asin(BigDecimal, MathContext)BigDecimalMath.cos(BigDecimal, MathContext)BigDecimalMath.acos(BigDecimal, MathContext)BigDecimalMath.tan(BigDecimal, MathContext)BigDecimalMath.atan(BigDecimal, MathContext)BigDecimalMath.atan2(BigDecimal, BigDecimal MathContext)BigDecimalMath.cot(BigDecimal, MathContext)BigDecimalMath.acot(BigDecimal, MathContext)BigDecimalMath.sinh(BigDecimal, MathContext)BigDecimalMath.cosh(BigDecimal, MathContext)BigDecimalMath.tanh(BigDecimal, MathContext)BigDecimalMath.coth(BigDecimal, MathContext)BigDecimalMath.asinh(BigDecimal, MathContext)BigDecimalMath.acosh(BigDecimal, MathContext)BigDecimalMath.atanh(BigDecimal, MathContext)BigDecimalMath.acoth(BigDecimal, MathContext)
Enhancements
Added BigDecimalMath.reciprocal()
The convenience method BigDecimalMath.reciprocal(BigDecimal, MathContext) was added.
Added BigComplexMath.factorial()
The method BigComplexMath.factorial(BigComplex x, MathContext mathContext) was added.
It calculates the factorial in the complex domain and is equivalent to BigDecimalMath.factorial(BigDecimal x, MathContext mathContext).
Added BigComplexMath.gamma()
The method BigComplexMath.gamma(BigComplex x, MathContext mathContext) was added.
It calculates the gamma function in the complex domain and is equivalent to BigDecimalMath.gamma(BigDecimal x, MathContext mathContext).
Added BigDecimalMath.toBigDecimal(String)
The BigDecimal(String) constructor as provided by Java gets increasingly slower if you pass longer strings to it.
The implementation in Java 11 and before is O(n^2).
If you want to convert very long strings (10000 characters or longer) then this slow constructor may become an issue.
BigDecimalMath.toBigDecimal(String) is a drop in replacement with the same functionality
(converting a string representation into a BigDecimal) but it is using a faster recursive implementation.
Improved performance of BigDecimalMath.factorial(int)
The factorial functions for integer values has been heavily optimized based on the beautiful implementation written by
Andriy Plokhotnyuk.
Thanks Andriy for giving permission to use it.
Examples
Note: The example code is available on github, but not part of the big-math library.
No changes in the examples.
Release 2.0.1
API changes
Module name for Java 9
Not really an API change but rather an API specification.
The deployed big-math Jar file contains now a module name for the Java 9 JigSaw module system.
This allows it to be used as automatic module with a well defined module name instead
of deriving the name magically from the Jar file name.
The module name follows the reverse domain convention and is: ch.obermuhlner.math.big
OSGi support
The big-math Jar file is now OSGi compatible.
The MANIFEST.MF contains all the necessary headers and exports the public packages
ch.obermuhlner.math.bigch.obermuhlner.math.big.stream
Bugfixes
Fixed BigDecimalMath.log(BigDecimal, MathContext) argument x very close to 0
BigDecimalMath.log(BigDecimal, MathContext) failed with arguments very close to 0 due toBigDecimal.doubleValue() rounding down to 0.
Fixed BigDecimalMath.atan2(BigDecimal, BigDecimal, MathContext) with positive x
A stupid typo in a division would give results with wrong precision results with positive x arguments.
Examples
Note: The example code is available on github, but not part of the big-math library.
No changes in the examples.
Release 2.0.0
API changes
Added BigComplex and BigComplexMath
Class BigComplex
The class BigComplex represents complex numbers in the form (a + bi).
It follows the design of BigDecimal with some convenience improvements like overloaded operator methods.
A big difference to BigDecimal is that BigComplex.equals() implements the mathematical equality
and not the strict technical equality.
This was a difficult decision because it means that BigComplex behaves slightly different than BigDecimal
but considering that the strange equality of BigDecimal is a major source of bugs we
decided it was worth the slight inconsistency.
If you need the strict equality use BigComplex.strictEquals().
reimadd(BigComplex)add(BigComplex, MathContext)add(BigDecimal)add(BigDecimal, MathContext)add(double)subtract(BigComplex)subtract(BigComplex, MathContext)subtract(BigDecimal)subtract(BigDecimal, MathContext)subtract(double)multiply(BigComplex)multiply(BigComplex, MathContext)multiply(BigDecimal)multiply(BigDecimal, MathContext)multiply(double)divide(BigComplex)divide(BigComplex, MathContext)divide(BigDecimal)divide(BigDecimal, MathContext)divide(double)reciprocal(MathContext)conjugate()negate()abs(MathContext)angle(MathContext)absSquare(MathContext)isReal()re()im()round(MathContext)hashCode()equals(Object)strictEquals(Object)toString()valueOf(BigDecimal)valueOf(double)valueOf(BigDecimal, BigDecimal)valueOf(double, double)valueOfPolar(BigDecimal, BigDecimal, MathContext)valueOfPolar(double, double, MathContext)
Class BigComplexMath
The class BigComplexMath is the equivalent of BigDecimalMath and contains mathematical functions in the complex domain.
sin(BigComplex, MathContext)cos(BigComplex, MathContext)tan(BigComplex, MathContext)asin(BigComplex, MathContext)acos(BigComplex, MathContext)atan(BigComplex, MathContext)acot(BigComplex, MathContext)exp(BigComplex, MathContext)log(BigComplex, MathContext)pow(BigComplex, long, MathContext)pow(BigComplex, BigDecimal, MathContext)pow(BigComplex, BigComplex, MathContext)sqrt(BigComplex, MathContext)root(BigComplex, BigDecimal, MathContext)root(BigComplex, BigComplex, MathContext)
Changed pow(BigDecimal, int) to pow(BigDecimal, long)
The signature of BigDecimalMath.pow(BigDecimal, int) to BigDecimalMath.pow(BigDecimal, long)
in order to improve the possible range of the y argument.
Bugfixes
Fix pow(BigDecimal, int) with large integer y argument
The BigDecimalMath.pow(BigDecimal, int) would give wrong results for large y values, because
internally BigDecimal.intValue() was used instead of BigDecimal.intValueExact().
This has been fixed and improved so that calculations with very large y values are still possible.
Precision improvements in log(), sqrt()
Strict unit testing has shown that the log() function would not calculate
with the maximum precision, especially if the x argument was transformed into
another value range (for example if x > 10).
This has been fixed by calculating the internal transformation calculations with a higher precision.
Examples
Note: The example code is available on github, but not part of the big-math library.
Added example HighPrecisionMath
The example class HighPrecisionMath was added to the examples.
The same class is also used in the FAQ section of the README.md on github.
Release 1.3.0
API changes
No API changes.
Bugfixes
No Bugfix changes.
Enhancements
Factory methods for BigDecimal and BigFloat streams
The classes BigDecimalStream and BigFloatStream provide factory methods for streams of BigDecimal respectively BigFloat elements.
Overloaded variants of range(start, end, step) provide sequential elements equivalent to IntStream.range(start, end) but with configurable step.
Similar methods for the rangeClosed() (inclusive end) are available.
The streams are well behaved when used in parallel mode.
The following code snippet:
System.out.println("Range [0, 10) step 1 (using BigDecimal as input parameters)"); BigDecimalStream.range(BigDecimal.valueOf(0), BigDecimal.valueOf(10), BigDecimal.ONE, mathContext) .forEach(System.out::println);
System.out.println("Range [0, 10) step 3 (using long as input parameters)"); BigDecimalStream.range(0, 10, 3, mathContext) .forEach(System.out::println);
produces this output:
Range [0, 10) step 1 (using BigDecimal as input parameters)
0
1
2
3
4
5
6
7
8
9
Range [0, 12] step 3 (using long as input parameters)
0
3
6
9
12
Added BigDecimalMath.atan2(y, x)
The atan2(y, x) function calculates the arc tangens (inverted tangens) of y / x in the range -π to π.
This is useful to calculate the angle θ from the conversion of rectangular
coordinates (x, y) to polar coordinates (r, θ).
Added BigFloat.signum() and convenience BigFloat.isNegative(), BigFloat.isZero(), BigFloat.isPositive()
The signum() function and its convenience variants where added to the BigFloat class:
BigFloat.signum()returns -1, 0, or 1 as the value is negative, zero, or positiveBigFloat.isNegative()returns whether the value is negativeBigFloat.isZero()returns whether the value is zeroBigFloat.isPositive()returns whether the value is positive
Examples
Note: The example code is available on github, but not part of the big-math library.
No changes in the examples.
Release 1.2.1
API changes
No API changes.
Bugfixes
BigDecimalMath.isDoubleValue() to return true for values abs(x) < Double.MIN_VALUE
Fixed isDoubleValue() to return true for values abs(x) < Double.MIN_VALUE.
For example BigDecimalMath.isDoubleValue(new BigDecimal("1E-325")) will return true
although this value is smaller than Double.MIN_VALUE (and therefore outside the range of values that can be represented as double)
because new BigDecimal("1E-325").doubleValue() returns 0 which is a legal value with loss of precision.
Enhancements
BigFloat.equals() tests mathematical identity, not technical
One of the most common problem for programmers using BigDecimal is probably that BigDecimal.equals() tests for technical identity,
not mathematical identity (the common workaround is to use compareTo() instead).
BigFloat.equals() tests for mathematical identity.
For exampleBigFloat.context(100).valueOf(123).equals(BigFloat.context(10).valueOf(123)) returns true.
Examples
Note: The example code is available on github, but not part of the big-math library.
No changes in the examples.

