From fdb7847bcd0de41a3ff9dc96e5a51038a5e0f609 Mon Sep 17 00:00:00 2001 From: Tec Date: Sun, 19 Jul 2020 11:30:33 +0200 Subject: Update decay logic --- .../java/ch/obermuhlner/math/big/BigComplex.java | 556 ------ .../ch/obermuhlner/math/big/BigComplexMath.java | 413 ----- .../ch/obermuhlner/math/big/BigDecimalMath.java | 1671 ----------------- .../java/ch/obermuhlner/math/big/BigFloat.java | 1947 -------------------- .../java/ch/obermuhlner/math/big/BigRational.java | 1103 ----------- .../math/big/DefaultBigDecimalMath.java | 736 -------- .../math/big/internal/AsinCalculator.java | 46 - .../math/big/internal/AtanhCalculator.java | 40 - .../math/big/internal/CosCalculator.java | 48 - .../math/big/internal/CoshCalculator.java | 43 - .../math/big/internal/ExpCalculator.java | 42 - .../math/big/internal/PowerIterator.java | 28 - .../math/big/internal/PowerNIterator.java | 33 - .../math/big/internal/PowerTwoNIterator.java | 33 - .../big/internal/PowerTwoNMinusOneIterator.java | 35 - .../big/internal/PowerTwoNPlusOneIterator.java | 33 - .../math/big/internal/SeriesCalculator.java | 127 -- .../math/big/internal/SinCalculator.java | 49 - .../math/big/internal/SinhCalculator.java | 44 - .../math/big/stream/BigDecimalStream.java | 219 --- .../math/big/stream/BigFloatStream.java | 214 --- 21 files changed, 7460 deletions(-) delete mode 100644 src/main/java/ch/obermuhlner/math/big/BigComplex.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/BigComplexMath.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/BigDecimalMath.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/BigFloat.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/BigRational.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/DefaultBigDecimalMath.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/AsinCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/AtanhCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/CosCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/CoshCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/ExpCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/PowerIterator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/PowerNIterator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNIterator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNMinusOneIterator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNPlusOneIterator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/SeriesCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/SinCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/internal/SinhCalculator.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/stream/BigDecimalStream.java delete mode 100644 src/main/java/ch/obermuhlner/math/big/stream/BigFloatStream.java (limited to 'src/main/java/ch') diff --git a/src/main/java/ch/obermuhlner/math/big/BigComplex.java b/src/main/java/ch/obermuhlner/math/big/BigComplex.java deleted file mode 100644 index a4620ff53b..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/BigComplex.java +++ /dev/null @@ -1,556 +0,0 @@ -package ch.obermuhlner.math.big; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Objects; - -/** - * Represents a complex number consisting of a real and an imaginary {@link BigDecimal} part in the form {@code a + bi}. - * - *

It generally follows the design of {@link BigDecimal} with some convenience improvements like overloaded operator methods.

- * - *

The biggest difference to {@link BigDecimal} is that {@link BigComplex#equals(Object) BigComplex.equals(Object)} implements the mathematical equality - * and not the strict technical equality. - * This was a difficult decision because it means that {@code BigComplex} behaves slightly different than {@link BigDecimal} - * but considering that the strange equality of {@link BigDecimal} is a major source of bugs we - * decided it was worth the slight inconsistency. - * If you need the strict equality use {@link BigComplex#strictEquals(Object)}`.

- * - *

This class is immutable and therefore inherently thread safe.

- */ -public final class BigComplex { - - /** - * Zero represented as complex number. - */ - public static final BigComplex ZERO = new BigComplex(BigDecimal.ZERO, BigDecimal.ZERO); - - /** - * Real 1 represented as complex number. - */ - public static final BigComplex ONE = new BigComplex(BigDecimal.ONE, BigDecimal.ZERO); - - /** - * Imaginary 1 represented as complex number. - */ - public static final BigComplex I = new BigComplex(BigDecimal.ZERO, BigDecimal.ONE); - - /** - * The real {@link BigDecimal} part of this complex number. - */ - public final BigDecimal re; - - /** - * The imaginary {@link BigDecimal} part of this complex number. - */ - public final BigDecimal im; - - private BigComplex(BigDecimal re, BigDecimal im) { - this.re = re; - this.im = im; - } - - /** - * Calculates the addition of the given complex value to this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigComplex} value to add - * @return the calculated {@link BigComplex} result - */ - public BigComplex add(BigComplex value) { - return valueOf( - re.add(value.re), - im.add(value.im)); - } - - /** - * Calculates the addition of the given complex value to this complex number using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigComplex} value to add - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex add(BigComplex value, MathContext mathContext) { - return valueOf( - re.add(value.re, mathContext), - im.add(value.im, mathContext)); - } - - /** - * Calculates the addition of the given real {@link BigDecimal} value to this complex number using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the real {@link BigDecimal} value to add - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex add(BigDecimal value, MathContext mathContext) { - return valueOf( - re.add(value, mathContext), - im); - } - - /** - * Calculates the addition of the given real {@link BigDecimal} value to this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the real {@link BigDecimal} value to add - * @return the calculated {@link BigComplex} result - */ - public BigComplex add(BigDecimal value) { - return valueOf( - re.add(value), - im); - } - - /** - * Calculates the addition of the given real {@code double} value to this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the real {@code double} value to add - * @return the calculated {@link BigComplex} result - */ - public BigComplex add(double value) { - return add(BigDecimal.valueOf(value)); - } - - /** - * Calculates the subtraction of the given complex value from this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigComplex} value to subtract - * @return the calculated {@link BigComplex} result - */ - public BigComplex subtract(BigComplex value) { - return valueOf( - re.subtract(value.re), - im.subtract(value.im)); - } - - /** - * Calculates the subtraction of the given complex value from this complex number using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigComplex} value to subtract - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex subtract(BigComplex value, MathContext mathContext) { - return valueOf( - re.subtract(value.re, mathContext), - im.subtract(value.im, mathContext)); - } - - /** - * Calculates the subtraction of the given real {@link BigDecimal} value from this complex number using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the real {@link BigDecimal} value to add - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex subtract(BigDecimal value, MathContext mathContext) { - return valueOf( - re.subtract(value, mathContext), - im); - } - - /** - * Calculates the subtraction of the given real {@link BigDecimal} value from this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the real {@link BigDecimal} value to subtract - * @return the calculated {@link BigComplex} result - */ - public BigComplex subtract(BigDecimal value) { - return valueOf( - re.subtract(value), - im); - } - - /** - * Calculates the subtraction of the given real {@code double} value from this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the real {@code double} value to subtract - * @return the calculated {@link BigComplex} result - */ - public BigComplex subtract(double value) { - return subtract(BigDecimal.valueOf(value)); - } - - /** - * Calculates the multiplication of the given complex value to this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigComplex} value to multiply - * @return the calculated {@link BigComplex} result - */ - public BigComplex multiply(BigComplex value) { - return valueOf( - re.multiply(value.re).subtract(im.multiply(value.im)), - re.multiply(value.im).add(im.multiply(value.re))); - } - - /** - * Calculates the multiplication of the given complex value with this complex number using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigComplex} value to multiply - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex multiply(BigComplex value, MathContext mathContext) { - return valueOf( - re.multiply(value.re, mathContext).subtract(im.multiply(value.im, mathContext), mathContext), - re.multiply(value.im, mathContext).add(im.multiply(value.re, mathContext), mathContext)); - } - - /** - * Calculates the multiplication of the given real {@link BigDecimal} value with this complex number using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the real {@link BigDecimal} value to multiply - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex multiply(BigDecimal value, MathContext mathContext) { - return valueOf( - re.multiply(value, mathContext), - im.multiply(value, mathContext)); - } - - /** - * Calculates the multiplication of the given real {@link BigDecimal} value with this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the real {@link BigDecimal} value to multiply - * @return the calculated {@link BigComplex} result - */ - public BigComplex multiply(BigDecimal value) { - return valueOf( - re.multiply(value), - im.multiply(value)); - } - - /** - * Calculates the multiplication of the given real {@code double} value with this complex number. - * - *

This methods does not modify this instance.

- * - * @param value the real {@code double} value to multiply - * @return the calculated {@link BigComplex} result - */ - public BigComplex multiply(double value) { - return multiply(BigDecimal.valueOf(value)); - } - - /** - * Calculates this complex number divided by the given complex value using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigComplex} value to divide by - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex divide(BigComplex value, MathContext mathContext) { - return multiply(value.reciprocal(mathContext), mathContext); - } - - /** - * Calculates this complex number divided by the given real {@link BigDecimal} value using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the {@link BigDecimal} value to divide by - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex divide(BigDecimal value, MathContext mathContext) { - return valueOf( - re.divide(value, mathContext), - im.divide(value, mathContext)); - } - - /** - * Calculates this complex number divided by the given real {@code double} value using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param value the {@code double} value to divide by - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex divide(double value, MathContext mathContext) { - return divide(BigDecimal.valueOf(value), mathContext); - } - - /** - * Calculates the reciprocal of this complex number using the specified {@link MathContext}. - * - *

This methods does not modify this instance.

- * - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigComplex reciprocal(MathContext mathContext) { - BigDecimal scale = absSquare(mathContext); - return valueOf( - re.divide(scale, mathContext), - im.negate().divide(scale, mathContext)); - } - - /** - * Calculates the conjugate {@code a - bi} of this complex number. - * - *

This methods does not modify this instance.

- * - * @return the calculated {@link BigComplex} result - */ - public BigComplex conjugate() { - return valueOf(re, im.negate()); - } - - /** - * Calculates the negation {@code -a - bi} of this complex number. - * - *

This methods does not modify this instance.

- * - * @return the calculated {@link BigComplex} result - */ - public BigComplex negate() { - return valueOf(re.negate(), im.negate()); - } - - /** - * Calculates the absolute value (also known as magnitude, length or radius) of this complex number. - * - *

This method is slower than {@link #absSquare(MathContext)} since it needs to calculate the {@link BigDecimalMath#sqrt(BigDecimal, MathContext)}.

- * - *

This methods does not modify this instance.

- * - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - * @see #absSquare(MathContext) - */ - public BigDecimal abs(MathContext mathContext) { - return BigDecimalMath.sqrt(absSquare(mathContext), mathContext); - } - - /** - * Calculates the angle in radians (also known as argument) of this complex number. - * - *

This methods does not modify this instance.

- * - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - */ - public BigDecimal angle(MathContext mathContext) { - return BigDecimalMath.atan2(im, re, mathContext); - } - - /** - * Calculates the square of the absolute value of this complex number. - * - *

This method is faster than {@link #abs(MathContext)} since it does not need to calculate the {@link BigDecimalMath#sqrt(BigDecimal, MathContext)}.

- * - *

This methods does not modify this instance.

- * - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - * @see #abs(MathContext) - */ - public BigDecimal absSquare(MathContext mathContext) { - return re.multiply(re, mathContext).add(im.multiply(im, mathContext), mathContext); - } - - /** - * Returns whether this complex number only has a real part (the imaginary part is 0). - * - * @return {@code true} if this complex number only has a real part, {@code false} if the imaginary part is not 0 - */ - public boolean isReal() { - return im.signum() == 0; - } - - /** - * Returns the real part of this complex number as {@link BigComplex} number. - * - * @return the real part as as {@link BigComplex} number - */ - public BigComplex re() { - return valueOf(re, BigDecimal.ZERO); - } - - /** - * Returns the imaginary part of this complex number as {@link BigComplex} number. - * - * @return the imaginary part as as {@link BigComplex} number - */ - public BigComplex im() { - return valueOf(BigDecimal.ZERO, im); - } - - /** - * Returns this complex nuber rounded to the specified precision. - * - *

This methods does not modify this instance.

- * - * @param mathContext the {@link MathContext} used to calculate the result - * @return the rounded {@link BigComplex} result - */ - public BigComplex round(MathContext mathContext) { - return valueOf(re.round(mathContext), im.round(mathContext)); - } - - @Override - public int hashCode() { - return Objects.hash(re, im); - } - - /** - * {@inheritDoc} - * - *

Contrary to {@link BigDecimal#equals(Object)} this method implements mathematical equality - * (by calling {@link BigDecimal#compareTo(BigDecimal)} on the real and imaginary parts) - * instead of strict equality.

- * - * @see #strictEquals(Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - BigComplex other = (BigComplex) obj; - - return re.compareTo(other.re) == 0 && im.compareTo(other.im) == 0; - } - - /** - * Returns whether the real and imaginary parts of this complex number are strictly equal. - * - *

This method uses the strict equality as defined by {@link BigDecimal#equals(Object)} on the real and imaginary parts.

- *

Please note that {@link #equals(Object) BigComplex.equals(Object)} implements mathematical equality instead - * (by calling {@link BigDecimal#compareTo(BigDecimal) on the real and imaginary parts}).

- * - * @param obj the object to compare for strict equality - * @return {@code true} if the specified object is strictly equal to this complex number - * @see #equals(Object) - */ - public boolean strictEquals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - BigComplex other = (BigComplex) obj; - - return re.equals(other.re) && im.equals(other.im); - } - - @Override - public String toString() { - if (im.signum() >= 0) { - return "(" + re + " + " + im + " i)"; - } else { - return "(" + re + " - " + im.negate() + " i)"; - } - } - - /** - * Returns a complex number with the specified real {@link BigDecimal} part. - * - * @param real the real {@link BigDecimal} part - * @return the complex number - */ - public static BigComplex valueOf(BigDecimal real) { - return valueOf(real, BigDecimal.ZERO); - } - - /** - * Returns a complex number with the specified real {@code double} part. - * - * @param real the real {@code double} part - * @return the complex number - */ - public static BigComplex valueOf(double real) { - return valueOf(BigDecimal.valueOf(real), BigDecimal.ZERO); - } - - /** - * Returns a complex number with the specified real and imaginary {@code double} parts. - * - * @param real the real {@code double} part - * @param imaginary the imaginary {@code double} part - * @return the complex number - */ - public static BigComplex valueOf(double real, double imaginary) { - return valueOf(BigDecimal.valueOf(real), BigDecimal.valueOf(imaginary)); - } - - /** - * Returns a complex number with the specified real and imaginary {@link BigDecimal} parts. - * - * @param real the real {@link BigDecimal} part - * @param imaginary the imaginary {@link BigDecimal} part - * @return the complex number - */ - public static BigComplex valueOf(BigDecimal real, BigDecimal imaginary) { - if (real.signum() == 0) { - if (imaginary.signum() == 0) { - return ZERO; - } - if (imaginary.compareTo(BigDecimal.ONE) == 0) { - return I; - } - } - if (imaginary.signum() == 0 && real.compareTo(BigDecimal.ONE) == 0) { - return ONE; - } - - return new BigComplex(real, imaginary); - } - - /** - * Returns a complex number with the specified polar {@link BigDecimal} radius and angle using the specified {@link MathContext}. - * - * @param radius the {@link BigDecimal} radius of the polar representation - * @param angle the {@link BigDecimal} angle in radians of the polar representation - * @param mathContext the {@link MathContext} used to calculate the result - * @return the complex number - */ - public static BigComplex valueOfPolar(BigDecimal radius, BigDecimal angle, MathContext mathContext) { - if (radius.signum() == 0) { - return ZERO; - } - - return valueOf( - radius.multiply(BigDecimalMath.cos(angle, mathContext), mathContext), - radius.multiply(BigDecimalMath.sin(angle, mathContext), mathContext)); - } - - public static BigComplex valueOfPolar(double radius, double angle, MathContext mathContext) { - return valueOfPolar(BigDecimal.valueOf(radius), BigDecimal.valueOf(angle), mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/BigComplexMath.java b/src/main/java/ch/obermuhlner/math/big/BigComplexMath.java deleted file mode 100644 index a73d9bccdd..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/BigComplexMath.java +++ /dev/null @@ -1,413 +0,0 @@ -package ch.obermuhlner.math.big; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.List; - -import static ch.obermuhlner.math.big.BigComplex.I; - -/** - * Provides advanced functions operating on {@link BigComplex}s. - */ -public class BigComplexMath { - - private static final BigDecimal TWO = BigDecimal.valueOf(2); - - /** - * Calculates the reciprocal of the given complex number using the specified {@link MathContext}. - * - * @param x the complex number to calculate the reciprocal - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - * @see BigComplex#reciprocal(MathContext) - */ - public static BigComplex reciprocal(BigComplex x, MathContext mathContext) { - return x.reciprocal(mathContext); - } - - /** - * Calculates the conjugate of the given complex number using the specified {@link MathContext}. - * - * @param x the complex number to calculate the conjugate - * @return the calculated {@link BigComplex} result - * @see BigComplex#conjugate() - */ - public static BigComplex conjugate(BigComplex x) { - return x.conjugate(); - } - - /** - * Calculates the absolute value (also known as magnitude, length or radius) of the given complex number using the specified {@link MathContext}. - * - * @param x the complex number to calculate the absolute value - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - * @see BigComplex#abs(MathContext) - */ - public static BigDecimal abs(BigComplex x, MathContext mathContext) { - return x.abs(mathContext); - } - - /** - * Calculates the square of the absolute value (also known as magnitude, length or radius) of the given complex number using the specified {@link MathContext}. - * - * @param x the complex number to calculate the square of the absolute value - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} result - * @see BigComplex#absSquare(MathContext) - */ - public static BigDecimal absSquare(BigComplex x, MathContext mathContext) { - return x.absSquare(mathContext); - } - - /** - * Calculates the angle in radians of the given complex number using the specified {@link MathContext}. - * - * @param x the complex number to calculate the angle - * @param mathContext the {@link MathContext} used to calculate the result - * @return the calculated {@link BigComplex} angle in radians - * @see BigComplex#angle(MathContext) - */ - public static BigDecimal angle(BigComplex x, MathContext mathContext) { - return x.angle(mathContext); - } - - /** - * Calculates the factorial of the specified {@link BigComplex}. - * - *

This implementation uses - * Spouge's approximation - * to calculate the factorial for non-integer values.

- * - *

This involves calculating a series of constants that depend on the desired precision. - * Since this constant calculation is quite expensive (especially for higher precisions), - * the constants for a specific precision will be cached - * and subsequent calls to this method with the same precision will be much faster.

- * - *

It is therefore recommended to do one call to this method with the standard precision of your application during the startup phase - * and to avoid calling it with many different precisions.

- * - *

See: Wikipedia: Factorial - Extension of factorial to non-integer values of argument

- * - * @param x the {@link BigComplex} - * @param mathContext the {@link MathContext} used for the result - * @return the factorial {@link BigComplex} - * @throws ArithmeticException if x is a negative integer value (-1, -2, -3, ...) - * @see BigDecimalMath#factorial(BigDecimal, MathContext) - * @see #gamma(BigComplex, MathContext) - */ - public static BigComplex factorial(BigComplex x, MathContext mathContext) { - if (x.isReal() && BigDecimalMath.isIntValue(x.re)) { - return BigComplex.valueOf(BigDecimalMath.factorial(x.re.intValueExact()).round(mathContext)); - } - - // https://en.wikipedia.org/wiki/Spouge%27s_approximation - MathContext mc = new MathContext(mathContext.getPrecision() * 2, mathContext.getRoundingMode()); - - int a = mathContext.getPrecision() * 13 / 10; - List constants = BigDecimalMath.getSpougeFactorialConstants(a); - - BigDecimal bigA = BigDecimal.valueOf(a); - - boolean negative = false; - BigComplex factor = BigComplex.valueOf(constants.get(0)); - for (int k = 1; k < a; k++) { - BigDecimal bigK = BigDecimal.valueOf(k); - factor = factor.add(BigComplex.valueOf(constants.get(k)).divide(x.add(bigK), mc), mc); - negative = !negative; - } - - BigComplex result = pow(x.add(bigA, mc), x.add(BigDecimal.valueOf(0.5), mc), mc); - result = result.multiply(exp(x.negate().subtract(bigA, mc), mc), mc); - result = result.multiply(factor, mc); - - return result.round(mathContext); - } - - /** - * Calculates the gamma function of the specified {@link BigComplex}. - * - *

This implementation uses {@link #factorial(BigComplex, MathContext)} internally, - * therefore the performance implications described there apply also for this method. - * - *

See: Wikipedia: Gamma function

- * - * @param x the {@link BigComplex} - * @param mathContext the {@link MathContext} used for the result - * @return the gamma {@link BigComplex} - * @throws ArithmeticException if x-1 is a negative integer value (-1, -2, -3, ...) - * @see BigDecimalMath#gamma(BigDecimal, MathContext) - * @see #factorial(BigComplex, MathContext) - */ - public static BigComplex gamma(BigComplex x, MathContext mathContext) { - return factorial(x.subtract(BigComplex.ONE), mathContext); - } - - - /** - * Calculates the natural exponent of {@link BigComplex} x (ex) in the complex domain. - * - *

See: Wikipedia: Exponent (Complex plane)

- * - * @param x the {@link BigComplex} to calculate the exponent for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated exponent {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex exp(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - BigDecimal expRe = BigDecimalMath.exp(x.re, mc); - return BigComplex.valueOf( - expRe.multiply(BigDecimalMath.cos(x.im, mc), mc).round(mathContext), - expRe.multiply(BigDecimalMath.sin(x.im, mc), mc)).round(mathContext); - } - - /** - * Calculates the sine (sinus) of {@link BigComplex} x in the complex domain. - * - *

See: Wikipedia: Sine (Sine with a complex argument)

- * - * @param x the {@link BigComplex} to calculate the sine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated sine {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex sin(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return BigComplex.valueOf( - BigDecimalMath.sin(x.re, mc).multiply(BigDecimalMath.cosh(x.im, mc), mc).round(mathContext), - BigDecimalMath.cos(x.re, mc).multiply(BigDecimalMath.sinh(x.im, mc), mc).round(mathContext)); - } - - /** - * Calculates the cosine (cosinus) of {@link BigComplex} x in the complex domain. - * - * @param x the {@link BigComplex} to calculate the cosine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated cosine {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex cos(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return BigComplex.valueOf( - BigDecimalMath.cos(x.re, mc).multiply(BigDecimalMath.cosh(x.im, mc), mc).round(mathContext), - BigDecimalMath.sin(x.re, mc).multiply(BigDecimalMath.sinh(x.im, mc), mc).negate().round(mathContext)); - } - - // - // http://scipp.ucsc.edu/~haber/archives/physics116A10/arc_10.pdf - - /** - * Calculates the tangens of {@link BigComplex} x in the complex domain. - * - * @param x the {@link BigComplex} to calculate the tangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated tangens {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex tan(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return sin(x, mc).divide(cos(x, mc), mc).round(mathContext); - } - - /** - * Calculates the arc tangens (inverted tangens) of {@link BigComplex} x in the complex domain. - * - *

See: Wikipedia: Inverse trigonometric functions (Extension to complex plane)

- * - * @param x the {@link BigComplex} to calculate the arc tangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc tangens {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex atan(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return log(I.subtract(x, mc).divide(I.add(x, mc), mc), mc).divide(I, mc).divide(TWO, mc).round(mathContext); - } - - /** - * Calculates the arc cotangens (inverted cotangens) of {@link BigComplex} x in the complex domain. - * - *

See: Wikipedia: Inverse trigonometric functions (Extension to complex plane)

- * - * @param x the {@link BigComplex} to calculate the arc cotangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc cotangens {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex acot(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return log(x.add(I, mc).divide(x.subtract(I, mc), mc), mc).divide(I, mc).divide(TWO, mc).round(mathContext); - } - - /** - * Calculates the arc sine (inverted sine) of {@link BigComplex} x in the complex domain. - * - *

See: Wikipedia: Inverse trigonometric functions (Extension to complex plane)

- * - * @param x the {@link BigComplex} to calculate the arc sine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc sine {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex asin(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return I.negate().multiply(log(I.multiply(x, mc).add(sqrt(BigComplex.ONE.subtract(x.multiply(x, mc), mc), mc), mc), mc), mc).round(mathContext); - } - - /** - * Calculates the arc cosine (inverted cosine) of {@link BigComplex} x in the complex domain. - * - *

See: Wikipedia: Inverse trigonometric functions (Extension to complex plane)

- * - * @param x the {@link BigComplex} to calculate the arc cosine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc cosine {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex acos(BigComplex x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return I.negate().multiply(log(x.add(sqrt(x.multiply(x, mc).subtract(BigComplex.ONE, mc), mc), mc), mc), mc).round(mathContext); - } - - /** - * Calculates the square root of {@link BigComplex} x in the complex domain (sqrt x). - * - *

See Wikipedia: Square root (Square root of an imaginary number)

- * - * @param x the {@link BigComplex} to calculate the square root for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated square root {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex sqrt(BigComplex x, MathContext mathContext) { - // https://math.stackexchange.com/questions/44406/how-do-i-get-the-square-root-of-a-complex-number - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - BigDecimal magnitude = x.abs(mc); - - BigComplex a = x.add(magnitude, mc); - return a.divide(a.abs(mc), mc).multiply(BigDecimalMath.sqrt(magnitude, mc), mc).round(mathContext); - } - - /** - * Calculates the natural logarithm of {@link BigComplex} x in the complex domain. - * - *

See: Wikipedia: Complex logarithm

- * - * @param x the {@link BigComplex} to calculate the natural logarithm for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated natural logarithm {@link BigComplex} with the precision specified in the mathContext - */ - public static BigComplex log(BigComplex x, MathContext mathContext) { - // https://en.wikipedia.org/wiki/Complex_logarithm - MathContext mc1 = new MathContext(mathContext.getPrecision() + 20, mathContext.getRoundingMode()); - MathContext mc2 = new MathContext(mathContext.getPrecision() + 5, mathContext.getRoundingMode()); - - return BigComplex.valueOf( - BigDecimalMath.log(x.abs(mc1), mc1).round(mathContext), - x.angle(mc2)).round(mathContext); - } - - /** - * Calculates {@link BigComplex} x to the power of long y (xy). - * - *

The implementation tries to minimize the number of multiplications of {@link BigComplex x} (using squares whenever possible).

- * - *

See: Wikipedia: Exponentiation - efficient computation

- * - * @param x the {@link BigComplex} value to take to the power - * @param y the long value to serve as exponent - * @param mathContext the {@link MathContext} used for the result - * @return the calculated x to the power of y with the precision specified in the mathContext - */ - public static BigComplex pow(BigComplex x, long y, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 10, mathContext.getRoundingMode()); - - if (y < 0) { - return BigComplex.ONE.divide(pow(x, -y, mc), mc).round(mathContext); - } - - BigComplex result = BigComplex.ONE; - while (y > 0) { - if ((y & 1) == 1) { - // odd exponent -> multiply result with x - result = result.multiply(x, mc); - y -= 1; - } - - if (y > 0) { - // even exponent -> square x - x = x.multiply(x, mc); - } - - y >>= 1; - } - - return result.round(mathContext); - } - - /** - * Calculates {@link BigComplex} x to the power of {@link BigDecimal} y (xy). - * - * @param x the {@link BigComplex} value to take to the power - * @param y the {@link BigDecimal} value to serve as exponent - * @param mathContext the {@link MathContext} used for the result - * @return the calculated x to the power of y with the precision specified in the mathContext - */ - public static BigComplex pow(BigComplex x, BigDecimal y, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - BigDecimal angleTimesN = x.angle(mc).multiply(y, mc); - return BigComplex.valueOf( - BigDecimalMath.cos(angleTimesN, mc), - BigDecimalMath.sin(angleTimesN, mc)).multiply(BigDecimalMath.pow(x.abs(mc), y, mc), mc).round(mathContext); - } - - /** - * Calculates {@link BigComplex} x to the power of {@link BigComplex} y (xy). - * - * @param x the {@link BigComplex} value to take to the power - * @param y the {@link BigComplex} value to serve as exponent - * @param mathContext the {@link MathContext} used for the result - * @return the calculated x to the power of y with the precision specified in the mathContext - */ - public static BigComplex pow(BigComplex x, BigComplex y, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return exp(y.multiply(log(x, mc), mc), mc).round(mathContext); - } - - /** - * Calculates the {@link BigDecimal} n'th root of {@link BigComplex} x (nsqrt x). - * - *

See Wikipedia: Square root

- * @param x the {@link BigComplex} value to calculate the n'th root - * @param n the {@link BigDecimal} defining the root - * @param mathContext the {@link MathContext} used for the result - * - * @return the calculated n'th root of x with the precision specified in the mathContext - */ - public static BigComplex root(BigComplex x, BigDecimal n, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return pow(x, BigDecimal.ONE.divide(n, mc), mc).round(mathContext); - } - - /** - * Calculates the {@link BigComplex} n'th root of {@link BigComplex} x (nsqrt x). - * - *

See Wikipedia: Square root

- * @param x the {@link BigComplex} value to calculate the n'th root - * @param n the {@link BigComplex} defining the root - * @param mathContext the {@link MathContext} used for the result - * - * @return the calculated n'th root of x with the precision specified in the mathContext - */ - public static BigComplex root(BigComplex x, BigComplex n, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - return pow(x, BigComplex.ONE.divide(n, mc), mc).round(mathContext); - } - - // TODO add root() for the k'th root - https://math.stackexchange.com/questions/322481/principal-nth-root-of-a-complex-number -} diff --git a/src/main/java/ch/obermuhlner/math/big/BigDecimalMath.java b/src/main/java/ch/obermuhlner/math/big/BigDecimalMath.java deleted file mode 100644 index 552331f3b4..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/BigDecimalMath.java +++ /dev/null @@ -1,1671 +0,0 @@ -package ch.obermuhlner.math.big; - -import static java.math.BigDecimal.ONE; -import static java.math.BigDecimal.TEN; -import static java.math.BigDecimal.ZERO; -import static java.math.BigDecimal.valueOf; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.*; - -import ch.obermuhlner.math.big.internal.AsinCalculator; -import ch.obermuhlner.math.big.internal.CosCalculator; -import ch.obermuhlner.math.big.internal.CoshCalculator; -import ch.obermuhlner.math.big.internal.ExpCalculator; -import ch.obermuhlner.math.big.internal.SinCalculator; -import ch.obermuhlner.math.big.internal.SinhCalculator; - -/** - * Provides advanced functions operating on {@link BigDecimal}s. - */ -public class BigDecimalMath { - - private static final BigDecimal TWO = valueOf(2); - private static final BigDecimal THREE = valueOf(3); - private static final BigDecimal MINUS_ONE = valueOf(-1); - private static final BigDecimal ONE_HALF = valueOf(0.5); - - private static final BigDecimal DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE); - - private static volatile BigDecimal log2Cache; - private static final Object log2CacheLock = new Object(); - - private static volatile BigDecimal log3Cache; - private static final Object log3CacheLock = new Object(); - - private static volatile BigDecimal log10Cache; - private static final Object log10CacheLock = new Object(); - - private static volatile BigDecimal piCache; - private static final Object piCacheLock = new Object(); - - private static volatile BigDecimal eCache; - private static final Object eCacheLock = new Object(); - - private static final BigDecimal ROUGHLY_TWO_PI = new BigDecimal("3.141592653589793").multiply(TWO); - - private static final int EXPECTED_INITIAL_PRECISION = 15; - - private static BigDecimal[] factorialCache = new BigDecimal[100]; - - static { - BigDecimal result = ONE; - factorialCache[0] = result; - for (int i = 1; i < factorialCache.length; i++) { - result = result.multiply(valueOf(i)); - factorialCache[i] = result; - } - } - - private static final Map> spougeFactorialConstantsCache = new HashMap<>(); - private static final Object spougeFactorialConstantsCacheLock = new Object(); - - private BigDecimalMath() { - // prevent instances - } - - /** - * Creates a {@link BigDecimal} from the specified String representation. - * - *

This method is equivalent to the String constructor {@link BigDecimal#BigDecimal(String)} - * but has been optimized for large strings (several thousand digits).

- * - * @param string the String representation - * @return the created {@link BigDecimal} - * @throws NumberFormatException if string is not a valid representation of a {@link BigDecimal} - * @see BigDecimal#BigDecimal(String) - * @see #toBigDecimal(String, MathContext) - */ - public static BigDecimal toBigDecimal(String string) { - return toBigDecimal(string, MathContext.UNLIMITED); - } - - /** - * Creates a {@link BigDecimal} from the specified String representation. - * - *

This method is equivalent to the String constructor {@link BigDecimal#BigDecimal(String, MathContext)} - * but has been optimized for large strings (several thousand digits).

- * - * @param string the string representation - * @param mathContext the {@link MathContext} used for the result - * @return the created {@link BigDecimal} - * @throws NumberFormatException if string is not a valid representation of a {@link BigDecimal} - * @throws ArithmeticException if the result is inexact but the rounding mode is {@code UNNECESSARY} - * @see BigDecimal#BigDecimal(String, MathContext) - * @see #toBigDecimal(String) - */ - public static BigDecimal toBigDecimal(String string, MathContext mathContext) { - int len = string.length(); - if (len < 600) { - return new BigDecimal(string, mathContext); - } - - int splitLength = len / (len >= 10000 ? 8 : 5); - return toBigDecimal(string, mathContext, splitLength); - } - - static BigDecimal toBigDecimal(String string, MathContext mathContext, int splitLength) { - int len = string.length(); - - if (len < splitLength) { - return new BigDecimal(string, mathContext); - } - - char[] chars = string.toCharArray(); - - boolean numberHasSign = false; - boolean negative = false; - int numberIndex = 0; - int dotIndex = -1; - int expIndex = -1; - boolean expHasSign = false; - int scale = 0; - - for (int i = 0; i < len; i++) { - char c = chars[i]; - switch (c) { - case '+': - if (expIndex >= 0) { - if (expHasSign) { - throw new NumberFormatException("Multiple signs in exponent"); - } - expHasSign = true; - } else { - if (numberHasSign) { - throw new NumberFormatException("Multiple signs in number"); - } - numberHasSign = true; - numberIndex = i + 1; - } - break; - case '-': - if (expIndex >= 0) { - if (expHasSign) { - throw new NumberFormatException("Multiple signs in exponent"); - } - expHasSign = true; - } else { - if (numberHasSign) { - throw new NumberFormatException("Multiple signs in number"); - } - numberHasSign = true; - negative = true; - numberIndex = i + 1; - } - break; - case 'e': - case 'E': - if (expIndex >= 0) { - throw new NumberFormatException("Multiple exponent markers"); - } - expIndex = i; - break; - case '.': - if (dotIndex >= 0) { - throw new NumberFormatException("Multiple decimal points"); - } - dotIndex = i; - break; - default: - if (dotIndex >= 0 && expIndex == -1) { - scale++; - } - } - } - - int numberEndIndex; - int exp = 0; - if (expIndex >= 0) { - numberEndIndex = expIndex; - String expString = new String(chars, expIndex + 1, len - expIndex - 1); - exp = Integer.parseInt(expString); - scale = adjustScale(scale, exp); - } else { - numberEndIndex = len; - } - - BigDecimal result; - - if (dotIndex >= 0) { - int leftLength = dotIndex - numberIndex; - BigDecimal bigDecimalLeft = toBigDecimalRecursive(chars, numberIndex, leftLength, exp, splitLength); - int rightLength = numberEndIndex - dotIndex - 1; - BigDecimal bigDecimalRight = toBigDecimalRecursive(chars, dotIndex + 1, rightLength, exp-rightLength, splitLength); - result = bigDecimalLeft.add(bigDecimalRight); - } else { - result = toBigDecimalRecursive(chars, numberIndex, numberEndIndex - numberIndex, exp, splitLength); - } - - if (scale != 0) { - result = result.setScale(scale); - } - - if (negative) { - result = result.negate(); - } - - if (mathContext.getPrecision() != 0) { - result = result.round(mathContext); - } - - return result; - } - - private static int adjustScale(int scale, long exp) { - long adjustedScale = scale - exp; - if (adjustedScale > Integer.MAX_VALUE || adjustedScale < Integer.MIN_VALUE) - throw new NumberFormatException("Scale out of range: " + adjustedScale + " while adjusting scale " + scale + " to exponent " + exp); - return (int) adjustedScale; - } - - private static BigDecimal toBigDecimalRecursive(char[] chars, int offset, int length, int scale, int splitLength) { - if (length > splitLength) { - int mid = length / 2; - BigDecimal bigDecimalLeft = toBigDecimalRecursive(chars, offset, mid, scale + length - mid, splitLength); - BigDecimal bigDecimalRight = toBigDecimalRecursive(chars, offset + mid, length - mid, scale, splitLength); - return bigDecimalLeft.add(bigDecimalRight); - } - if (length == 0) { - return BigDecimal.ZERO; - } - return new BigDecimal(chars, offset, length).movePointRight(scale); - } - - /** - * Returns whether the specified {@link BigDecimal} value can be represented as int. - * - *

If this returns true you can call {@link BigDecimal#intValueExact()} without fear of an {@link ArithmeticException}.

- * - * @param value the {@link BigDecimal} to check - * @return true if the value can be represented as int value - */ - public static boolean isIntValue(BigDecimal value) { - // TODO impl isIntValue() without exceptions - try { - value.intValueExact(); - return true; - } catch (ArithmeticException ex) { - // ignored - } - return false; - } - - /** - * Returns whether the specified {@link BigDecimal} value can be represented as long. - * - *

If this returns true you can call {@link BigDecimal#longValueExact()} without fear of an {@link ArithmeticException}.

- * - * @param value the {@link BigDecimal} to check - * @return true if the value can be represented as long value - */ - public static boolean isLongValue(BigDecimal value) { - // TODO impl isLongValue() without exceptions - try { - value.longValueExact(); - return true; - } catch (ArithmeticException ex) { - // ignored - } - return false; - } - - /** - * Returns whether the specified {@link BigDecimal} value can be represented as double. - * - *

If this returns true you can call {@link BigDecimal#doubleValue()} - * without fear of getting {@link Double#POSITIVE_INFINITY} or {@link Double#NEGATIVE_INFINITY} as result.

- * - *

Example: BigDecimalMath.isDoubleValue(new BigDecimal("1E309")) returns false, - * because new BigDecimal("1E309").doubleValue() returns Infinity.

- * - *

Note: This method does not check for possible loss of precision.

- * - *

For example BigDecimalMath.isDoubleValue(new BigDecimal("1.23400000000000000000000000000000001")) will return true, - * because new BigDecimal("1.23400000000000000000000000000000001").doubleValue() returns a valid double value, - * although it loses precision and returns 1.234.

- * - *

BigDecimalMath.isDoubleValue(new BigDecimal("1E-325")) will return true - * although this value is smaller than {@link 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.

- * - * @param value the {@link BigDecimal} to check - * @return true if the value can be represented as double value - */ - public static boolean isDoubleValue(BigDecimal value) { - if (value.compareTo(DOUBLE_MAX_VALUE) > 0) { - return false; - } - if (value.compareTo(DOUBLE_MAX_VALUE.negate()) < 0) { - return false; - } - - return true; - } - - /** - * Returns the mantissa of the specified {@link BigDecimal} written as mantissa * 10exponent. - * - *

The mantissa is defined as having exactly 1 digit before the decimal point.

- * - * @param value the {@link BigDecimal} - * @return the mantissa - * @see #exponent(BigDecimal) - */ - public static BigDecimal mantissa(BigDecimal value) { - int exponent = exponent(value); - if (exponent == 0) { - return value; - } - - return value.movePointLeft(exponent); - } - - /** - * Returns the exponent of the specified {@link BigDecimal} written as mantissa * 10exponent. - * - *

The mantissa is defined as having exactly 1 digit before the decimal point.

- * - * @param value the {@link BigDecimal} - * @return the exponent - * @see #mantissa(BigDecimal) - */ - public static int exponent(BigDecimal value) { - return value.precision() - value.scale() - 1; - } - - /** - * Returns the number of significant digits of the specified {@link BigDecimal}. - * - *

The result contains the number of all digits before the decimal point and - * all digits after the decimal point excluding trailing zeroes.

- * - *

Examples:

- *
    - *
  • significantDigits(new BigDecimal("12300.00")) returns 5
  • - *
  • significantDigits(new BigDecimal("1.23000")) returns 3
  • - *
  • significantDigits(new BigDecimal("0.00012300")) returns 3
  • - *
  • significantDigits(new BigDecimal("12300.4500")) returns 7
  • - *
- * - *

See: Wikipedia: Significant figures

- * - * @param value the {@link BigDecimal} - * @return the number of significant digits - * @see BigDecimal#stripTrailingZeros() - * @see BigDecimal#precision() - */ - public static int significantDigits(BigDecimal value) { - BigDecimal stripped = value.stripTrailingZeros(); - if (stripped.scale() >= 0) { - return stripped.precision(); - } else { - return stripped.precision() - stripped.scale(); - } - } - - /** - * Returns the integral part of the specified {@link BigDecimal} (left of the decimal point). - * - * @param value the {@link BigDecimal} - * @return the integral part - * @see #fractionalPart(BigDecimal) - */ - public static BigDecimal integralPart(BigDecimal value) { - return value.setScale(0, BigDecimal.ROUND_DOWN); - } - - /** - * Returns the fractional part of the specified {@link BigDecimal} (right of the decimal point). - * - * @param value the {@link BigDecimal} - * @return the fractional part - * @see #integralPart(BigDecimal) - */ - public static BigDecimal fractionalPart(BigDecimal value) { - return value.subtract(integralPart(value)); - } - - /** - * Rounds the specified {@link BigDecimal} to the precision of the specified {@link MathContext}. - * - *

This method calls {@link BigDecimal#round(MathContext)}.

- * - * @param value the {@link BigDecimal} to round - * @param mathContext the {@link MathContext} used for the result - * @return the rounded {@link BigDecimal} value - * @see BigDecimal#round(MathContext) - * @see BigDecimalMath#roundWithTrailingZeroes(BigDecimal, MathContext) - */ - public static BigDecimal round(BigDecimal value, MathContext mathContext) { - return value.round(mathContext); - } - - /** - * Rounds the specified {@link BigDecimal} to the precision of the specified {@link MathContext} including trailing zeroes. - * - *

This method is similar to {@link BigDecimal#round(MathContext)} but does not remove the 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
-
- * - * @param value the {@link BigDecimal} to round - * @param mathContext the {@link MathContext} used for the result - * @return the rounded {@link BigDecimal} value including trailing zeroes - * @see BigDecimal#round(MathContext) - * @see BigDecimalMath#round(BigDecimal, MathContext) - */ - public static BigDecimal roundWithTrailingZeroes(BigDecimal value, MathContext mathContext) { - if (value.precision() == mathContext.getPrecision()) { - return value; - } - if (value.signum() == 0) { - return BigDecimal.ZERO.setScale(mathContext.getPrecision() - 1); - } - - try { - BigDecimal stripped = value.stripTrailingZeros(); - int exponentStripped = exponent(stripped); // value.precision() - value.scale() - 1; - - BigDecimal zero; - if (exponentStripped < -1) { - zero = BigDecimal.ZERO.setScale(mathContext.getPrecision() - exponentStripped); - } else { - zero = BigDecimal.ZERO.setScale(mathContext.getPrecision() + exponentStripped + 1); - } - return stripped.add(zero, mathContext); - } catch (ArithmeticException ex) { - return value.round(mathContext); - } - } - - /** - * Calculates the reciprocal of the specified {@link BigDecimal}. - * - * @param x the {@link BigDecimal} - * @param mathContext the {@link MathContext} used for the result - * @return the reciprocal {@link BigDecimal} - * @throws ArithmeticException if x = 0 - * @throws ArithmeticException if the result is inexact but the - * rounding mode is {@code UNNECESSARY} or - * {@code mc.precision == 0} and the quotient has a - * non-terminating decimal expansion. - */ - public static BigDecimal reciprocal(BigDecimal x, MathContext mathContext) { - return BigDecimal.ONE.divide(x, mathContext); - } - - /** - * Calculates the factorial of the specified integer argument. - * - *

factorial = 1 * 2 * 3 * ... n

- * - * @param n the {@link BigDecimal} - * @return the factorial {@link BigDecimal} - * @throws ArithmeticException if x < 0 - */ - public static BigDecimal factorial(int n) { - if (n < 0) { - throw new ArithmeticException("Illegal factorial(n) for n < 0: n = " + n); - } - if (n < factorialCache.length) { - return factorialCache[n]; - } - - BigDecimal result = factorialCache[factorialCache.length - 1]; - return result.multiply(factorialRecursion(factorialCache.length, n)); - } - - private static BigDecimal factorialLoop(int n1, final int n2) { - final long limit = Long.MAX_VALUE / n2; - long accu = 1; - BigDecimal result = BigDecimal.ONE; - while (n1 <= n2) { - if (accu <= limit) { - accu *= n1; - } else { - result = result.multiply(BigDecimal.valueOf(accu)); - accu = n1; - } - n1++; - } - return result.multiply(BigDecimal.valueOf(accu)); - } - - private static BigDecimal factorialRecursion(final int n1, final int n2) { - int threshold = n1 > 200 ? 80 : 150; - if (n2 - n1 < threshold) { - return factorialLoop(n1, n2); - } - final int mid = (n1 + n2) >> 1; - return factorialRecursion(mid + 1, n2).multiply(factorialRecursion(n1, mid)); - } - - /** - * Calculates the factorial of the specified {@link BigDecimal}. - * - *

This implementation uses - * Spouge's approximation - * to calculate the factorial for non-integer values.

- * - *

This involves calculating a series of constants that depend on the desired precision. - * Since this constant calculation is quite expensive (especially for higher precisions), - * the constants for a specific precision will be cached - * and subsequent calls to this method with the same precision will be much faster.

- * - *

It is therefore recommended to do one call to this method with the standard precision of your application during the startup phase - * and to avoid calling it with many different precisions.

- * - *

See: Wikipedia: Factorial - Extension of factorial to non-integer values of argument

- * - * @param x the {@link BigDecimal} - * @param mathContext the {@link MathContext} used for the result - * @return the factorial {@link BigDecimal} - * @throws ArithmeticException if x is a negative integer value (-1, -2, -3, ...) - * @throws UnsupportedOperationException if x is a non-integer value and the {@link MathContext} has unlimited precision - * @see #factorial(int) - * @see #gamma(BigDecimal, MathContext) - */ - public static BigDecimal factorial(BigDecimal x, MathContext mathContext) { - if (isIntValue(x)) { - return round(factorial(x.intValueExact()), mathContext); - } - - // https://en.wikipedia.org/wiki/Spouge%27s_approximation - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() << 1, mathContext.getRoundingMode()); - - int a = mathContext.getPrecision() * 13 / 10; - List constants = getSpougeFactorialConstants(a); - - BigDecimal bigA = BigDecimal.valueOf(a); - - boolean negative = false; - BigDecimal factor = constants.get(0); - for (int k = 1; k < a; k++) { - BigDecimal bigK = BigDecimal.valueOf(k); - factor = factor.add(constants.get(k).divide(x.add(bigK), mc)); - negative = !negative; - } - - BigDecimal result = pow(x.add(bigA), x.add(BigDecimal.valueOf(0.5)), mc); - result = result.multiply(exp(x.negate().subtract(bigA), mc)); - result = result.multiply(factor); - - return round(result, mathContext); - } - - static List getSpougeFactorialConstants(int a) { - synchronized (spougeFactorialConstantsCacheLock) { - return spougeFactorialConstantsCache.computeIfAbsent(a, key -> { - List constants = new ArrayList<>(a); - MathContext mc = new MathContext(a * 15 / 10); - - BigDecimal c0 = sqrt(pi(mc).multiply(TWO, mc), mc); - constants.add(c0); - - boolean negative = false; - for (int k = 1; k < a; k++) { - BigDecimal bigK = BigDecimal.valueOf(k); - long deltaAK = (long)a - k; - BigDecimal ck = pow(BigDecimal.valueOf(deltaAK), bigK.subtract(ONE_HALF), mc); - ck = ck.multiply(exp(BigDecimal.valueOf(deltaAK), mc), mc); - ck = ck.divide(factorial(k - 1), mc); - if (negative) { - ck = ck.negate(); - } - constants.add(ck); - - negative = !negative; - } - - return Collections.unmodifiableList(constants); - }); - } - } - - /** - * Calculates the gamma function of the specified {@link BigDecimal}. - * - *

This implementation uses {@link #factorial(BigDecimal, MathContext)} internally, - * therefore the performance implications described there apply also for this method. - * - *

See: Wikipedia: Gamma function

- * - * @param x the {@link BigDecimal} - * @param mathContext the {@link MathContext} used for the result - * @return the gamma {@link BigDecimal} - * @throws ArithmeticException if x-1 is a negative integer value (-1, -2, -3, ...) - * @throws UnsupportedOperationException if x is a non-integer value and the {@link MathContext} has unlimited precision - * @see #factorial(BigDecimal, MathContext) - */ - public static BigDecimal gamma(BigDecimal x, MathContext mathContext) { - return factorial(x.subtract(ONE), mathContext); - } - - /** - * Calculates the Bernoulli number for the specified index. - * - *

This function calculates the first Bernoulli numbers and therefore bernoulli(1) returns -0.5

- *

Note that bernoulli(x) for all odd x > 1 returns 0

- *

See: Wikipedia: Bernoulli number

- * - * @param n the index of the Bernoulli number to be calculated (starting at 0) - * @param mathContext the {@link MathContext} used for the result - * @return the Bernoulli number for the specified index - * @throws ArithmeticException if x < 0 - * @throws ArithmeticException if the result is inexact but the - * rounding mode is {@code UNNECESSARY} or - * {@code mc.precision == 0} and the quotient has a - * non-terminating decimal expansion. - */ - public static BigDecimal bernoulli(int n, MathContext mathContext) { - if (n < 0) { - throw new ArithmeticException("Illegal bernoulli(n) for n < 0: n = " + n); - } - - BigRational b = BigRational.bernoulli(n); - return b.toBigDecimal(mathContext); - } - - /** - * Calculates {@link BigDecimal} x to the power of {@link BigDecimal} y (xy). - * - * @param x the {@link BigDecimal} value to take to the power - * @param y the {@link BigDecimal} value to serve as exponent - * @param mathContext the {@link MathContext} used for the result - * @return the calculated x to the power of y with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - * @see #pow(BigDecimal, long, MathContext) - */ - public static BigDecimal pow(BigDecimal x, BigDecimal y, MathContext mathContext) { - checkMathContext(mathContext); - if (x.signum() == 0) { - switch (y.signum()) { - case 0 : return round(ONE, mathContext); - case 1 : return round(ZERO, mathContext); - } - } - - // TODO optimize y=0, y=1, y=10^k, y=-1, y=-10^k - - try { - long longValue = y.longValueExact(); - return pow(x, longValue, mathContext); - } catch (ArithmeticException ex) { - // ignored - } - - if (fractionalPart(y).signum() == 0) { - return powInteger(x, y, mathContext); - } - - // x^y = exp(y*log(x)) - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - BigDecimal result = exp(y.multiply(log(x, mc), mc), mc); - - return round(result, mathContext); - } - - /** - * Calculates {@link BigDecimal} x to the power of long y (xy). - * - *

The implementation tries to minimize the number of multiplications of {@link BigDecimal x} (using squares whenever possible).

- * - *

See: Wikipedia: Exponentiation - efficient computation

- * - * @param x the {@link BigDecimal} value to take to the power - * @param y the long value to serve as exponent - * @param mathContext the {@link MathContext} used for the result - * @return the calculated x to the power of y with the precision specified in the mathContext - * @throws ArithmeticException if y is negative and the result is inexact but the - * rounding mode is {@code UNNECESSARY} or - * {@code mc.precision == 0} and the quotient has a - * non-terminating decimal expansion. - * @throws ArithmeticException if the rounding mode is - * {@code UNNECESSARY} and the - * {@code BigDecimal} operation would require rounding. - */ - public static BigDecimal pow(BigDecimal x, long y, MathContext mathContext) { - MathContext mc = mathContext.getPrecision() == 0 ? mathContext : new MathContext(mathContext.getPrecision() + 10, mathContext.getRoundingMode()); - - // TODO optimize y=0, y=1, y=10^k, y=-1, y=-10^k - - if (y < 0) { - BigDecimal value = reciprocal(pow(x, -y, mc), mc); - return round(value, mathContext); - } - - BigDecimal result = ONE; - while (y > 0) { - if ((y & 1) == 1) { - // odd exponent -> multiply result with x - result = result.multiply(x, mc); - y -= 1; - } - - if (y > 0) { - // even exponent -> square x - x = x.multiply(x, mc); - } - - y >>= 1; - } - - return round(result, mathContext); - } - - /** - * Calculates {@link BigDecimal} x to the power of the integer value y (xy). - * - *

The value y MUST be an integer value.

- * - * @param x the {@link BigDecimal} value to take to the power - * @param integerY the {@link BigDecimal} integer value to serve as exponent - * @param mathContext the {@link MathContext} used for the result - * @return the calculated x to the power of y with the precision specified in the mathContext - * @see #pow(BigDecimal, long, MathContext) - */ - private static BigDecimal powInteger(BigDecimal x, BigDecimal integerY, MathContext mathContext) { - if (fractionalPart(integerY).signum() != 0) { - throw new IllegalArgumentException("Not integer value: " + integerY); - } - - if (integerY.signum() < 0) { - return ONE.divide(powInteger(x, integerY.negate(), mathContext), mathContext); - } - - MathContext mc = new MathContext(Math.max(mathContext.getPrecision(), -integerY.scale()) + 30, mathContext.getRoundingMode()); - - BigDecimal result = ONE; - while (integerY.signum() > 0) { - BigDecimal halfY = integerY.divide(TWO, mc); - - if (fractionalPart(halfY).signum() != 0) { - // odd exponent -> multiply result with x - result = result.multiply(x, mc); - integerY = integerY.subtract(ONE); - halfY = integerY.divide(TWO, mc); - } - - if (halfY.signum() > 0) { - // even exponent -> square x - x = x.multiply(x, mc); - } - - integerY = halfY; - } - - return round(result, mathContext); - } - - /** - * Calculates the square root of {@link BigDecimal} x. - * - *

See Wikipedia: Square root

- * - * @param x the {@link BigDecimal} value to calculate the square root - * @param mathContext the {@link MathContext} used for the result - * @return the calculated square root of x with the precision specified in the mathContext - * @throws ArithmeticException if x < 0 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal sqrt(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - switch (x.signum()) { - case 0: - return ZERO; - case -1: - throw new ArithmeticException("Illegal sqrt(x) for x < 0: x = " + x); - } - - int maxPrecision = mathContext.getPrecision() + 6; - BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1); - - BigDecimal result; - int adaptivePrecision; - if (isDoubleValue(x)) { - result = BigDecimal.valueOf(Math.sqrt(x.doubleValue())); - adaptivePrecision = EXPECTED_INITIAL_PRECISION; - } else { - result = x.multiply(ONE_HALF, mathContext); - adaptivePrecision = 1; - } - - BigDecimal last; - - if (adaptivePrecision < maxPrecision) { - if (result.multiply(result).compareTo(x) == 0) { - return round(result, mathContext); // early exit if x is a square number - } - - do { - last = result; - adaptivePrecision <<= 1; - if (adaptivePrecision > maxPrecision) { - adaptivePrecision = maxPrecision; - } - MathContext mc = new MathContext(adaptivePrecision, mathContext.getRoundingMode()); - result = x.divide(result, mc).add(last).multiply(ONE_HALF, mc); - } - while (adaptivePrecision < maxPrecision || result.subtract(last).abs().compareTo(acceptableError) > 0); - } - - return round(result, mathContext); - } - - /** - * Calculates the n'th root of {@link BigDecimal} x. - * - *

See Wikipedia: Square root

- * @param x the {@link BigDecimal} value to calculate the n'th root - * @param n the {@link BigDecimal} defining the root - * @param mathContext the {@link MathContext} used for the result - * - * @return the calculated n'th root of x with the precision specified in the mathContext - * @throws ArithmeticException if x < 0 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal root(BigDecimal x, BigDecimal n, MathContext mathContext) { - checkMathContext(mathContext); - switch (x.signum()) { - case 0: - return ZERO; - case -1: - throw new ArithmeticException("Illegal root(x) for x < 0: x = " + x); - } - - if (n.compareTo(BigDecimal.ONE) <= 0) { - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - return pow(x, BigDecimal.ONE.divide(n, mc), mathContext); - } - - int maxPrecision = mathContext.getPrecision() + 4; - BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1); - - BigDecimal nMinus1 = n.subtract(ONE); - BigDecimal result = x.divide(TWO, MathContext.DECIMAL32); - int adaptivePrecision = 2; // first approximation has really bad precision - BigDecimal step; - - do { - adaptivePrecision *= 3; - if (adaptivePrecision > maxPrecision) { - adaptivePrecision = maxPrecision; - } - MathContext mc = new MathContext(adaptivePrecision, mathContext.getRoundingMode()); - - step = x.divide(pow(result, nMinus1, mc), mc).subtract(result).divide(n, mc); - result = result.add(step); - } while (adaptivePrecision < maxPrecision || step.abs().compareTo(acceptableError) > 0); - - return round(result, mathContext); - } - - /** - * Calculates the natural logarithm of {@link BigDecimal} x. - * - *

See: Wikipedia: Natural logarithm

- * - * @param x the {@link BigDecimal} to calculate the natural logarithm for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated natural logarithm {@link BigDecimal} with the precision specified in the mathContext - * @throws ArithmeticException if x <= 0 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal log(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - if (x.signum() <= 0) { - throw new ArithmeticException("Illegal log(x) for x <= 0: x = " + x); - } - if (x.compareTo(ONE) == 0) { - return ZERO; - } - - BigDecimal result; - switch (x.compareTo(TEN)) { - case 0: - result = logTen(mathContext); - break; - case 1: - result = logUsingExponent(x, mathContext); - break; - default : - result = logUsingTwoThree(x, mathContext); - } - - return round(result, mathContext); - } - - /** - * Calculates the logarithm of {@link BigDecimal} x to the base 2. - * - * @param x the {@link BigDecimal} to calculate the logarithm base 2 for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated natural logarithm {@link BigDecimal} to the base 2 with the precision specified in the mathContext - * @throws ArithmeticException if x <= 0 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal log2(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - - BigDecimal result = log(x, mc).divide(logTwo(mc), mc); - return round(result, mathContext); - } - - /** - * Calculates the logarithm of {@link BigDecimal} x to the base 10. - * - * @param x the {@link BigDecimal} to calculate the logarithm base 10 for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated natural logarithm {@link BigDecimal} to the base 10 with the precision specified in the mathContext - * @throws ArithmeticException if x <= 0 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal log10(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 2, mathContext.getRoundingMode()); - - BigDecimal result = log(x, mc).divide(logTen(mc), mc); - return round(result, mathContext); - } - - private static BigDecimal logUsingNewton(BigDecimal x, MathContext mathContext) { - // https://en.wikipedia.org/wiki/Natural_logarithm in chapter 'High Precision' - // y = y + 2 * (x-exp(y)) / (x+exp(y)) - - int maxPrecision = mathContext.getPrecision() + 20; - BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1); - //System.out.println("logUsingNewton(" + x + " " + mathContext + ") precision " + maxPrecision); - - BigDecimal result; - int adaptivePrecision; - double doubleX = x.doubleValue(); - if (doubleX > 0.0 && isDoubleValue(x)) { - result = BigDecimal.valueOf(Math.log(doubleX)); - adaptivePrecision = EXPECTED_INITIAL_PRECISION; - } else { - result = x.divide(TWO, mathContext); - adaptivePrecision = 1; - } - - BigDecimal step; - - do { - adaptivePrecision *= 3; - if (adaptivePrecision > maxPrecision) { - adaptivePrecision = maxPrecision; - } - MathContext mc = new MathContext(adaptivePrecision, mathContext.getRoundingMode()); - - BigDecimal expY = BigDecimalMath.exp(result, mc); - step = TWO.multiply(x.subtract(expY)).divide(x.add(expY), mc); - //System.out.println(" step " + step + " adaptivePrecision=" + adaptivePrecision); - result = result.add(step); - } while (adaptivePrecision < maxPrecision || step.abs().compareTo(acceptableError) > 0); - - return result; - } - - private static BigDecimal logUsingExponent(BigDecimal x, MathContext mathContext) { - MathContext mcDouble = new MathContext(mathContext.getPrecision() << 1, mathContext.getRoundingMode()); - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - //System.out.println("logUsingExponent(" + x + " " + mathContext + ") precision " + mc); - - int exponent = exponent(x); - BigDecimal mantissa = mantissa(x); - - BigDecimal result = logUsingTwoThree(mantissa, mc); - if (exponent != 0) { - result = result.add(valueOf(exponent).multiply(logTen(mcDouble), mc)); - } - return result; - } - - private static BigDecimal logUsingTwoThree(BigDecimal x, MathContext mathContext) { - MathContext mcDouble = new MathContext(mathContext.getPrecision() << 1, mathContext.getRoundingMode()); - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - //System.out.println("logUsingTwoThree(" + x + " " + mathContext + ") precision " + mc); - - int factorOfTwo = 0; - int powerOfTwo = 1; - int factorOfThree = 0; - int powerOfThree = 1; - - double value = x.doubleValue(); - if (value < 0.01) { - // do nothing - } else if (value < 0.1) { // never happens when called by logUsingExponent() - while (value < 0.6) { - value *= 2; - factorOfTwo--; - powerOfTwo <<= 1; - } - } - else if (value < 0.115) { // (0.1 - 0.11111 - 0.115) -> (0.9 - 1.0 - 1.035) - factorOfThree = -2; - powerOfThree = 9; - } - else if (value < 0.14) { // (0.115 - 0.125 - 0.14) -> (0.92 - 1.0 - 1.12) - factorOfTwo = -3; - powerOfTwo = 8; - } - else if (value < 0.2) { // (0.14 - 0.16667 - 0.2) - (0.84 - 1.0 - 1.2) - factorOfTwo = -1; - powerOfTwo = 2; - factorOfThree = -1; - powerOfThree = 3; - } - else if (value < 0.3) { // (0.2 - 0.25 - 0.3) -> (0.8 - 1.0 - 1.2) - factorOfTwo = -2; - powerOfTwo = 4; - } - else if (value < 0.42) { // (0.3 - 0.33333 - 0.42) -> (0.9 - 1.0 - 1.26) - factorOfThree = -1; - powerOfThree = 3; - } - else if (value < 0.7) { // (0.42 - 0.5 - 0.7) -> (0.84 - 1.0 - 1.4) - factorOfTwo = -1; - powerOfTwo = 2; - } - else if (value < 1.4) { // (0.7 - 1.0 - 1.4) -> (0.7 - 1.0 - 1.4) - // do nothing - } - else if (value < 2.5) { // (1.4 - 2.0 - 2.5) -> (0.7 - 1.0 - 1.25) - factorOfTwo = 1; - powerOfTwo = 2; - } - else if (value < 3.5) { // (2.5 - 3.0 - 3.5) -> (0.833333 - 1.0 - 1.166667) - factorOfThree = 1; - powerOfThree = 3; - } - else if (value < 5.0) { // (3.5 - 4.0 - 5.0) -> (0.875 - 1.0 - 1.25) - factorOfTwo = 2; - powerOfTwo = 4; - } - else if (value < 7.0) { // (5.0 - 6.0 - 7.0) -> (0.833333 - 1.0 - 1.166667) - factorOfThree = 1; - powerOfThree = 3; - factorOfTwo = 1; - powerOfTwo = 2; - } - else if (value < 8.5) { // (7.0 - 8.0 - 8.5) -> (0.875 - 1.0 - 1.0625) - factorOfTwo = 3; - powerOfTwo = 8; - } - else if (value < 10.0) { // (8.5 - 9.0 - 10.0) -> (0.94444 - 1.0 - 1.11111) - factorOfThree = 2; - powerOfThree = 9; - } - else { - while (value > 1.4) { // never happens when called by logUsingExponent() - value /= 2; - factorOfTwo++; - powerOfTwo <<= 1; - } - } - - BigDecimal correctedX = x; - BigDecimal result = ZERO; - - if (factorOfTwo > 0) { - correctedX = correctedX.divide(valueOf(powerOfTwo), mc); - result = result.add(logTwo(mcDouble).multiply(valueOf(factorOfTwo), mc)); - } - else if (factorOfTwo < 0) { - correctedX = correctedX.multiply(valueOf(powerOfTwo), mc); - result = result.subtract(logTwo(mcDouble).multiply(valueOf(-factorOfTwo), mc)); - } - - if (factorOfThree > 0) { - correctedX = correctedX.divide(valueOf(powerOfThree), mc); - result = result.add(logThree(mcDouble).multiply(valueOf(factorOfThree), mc)); - } - else if (factorOfThree < 0) { - correctedX = correctedX.multiply(valueOf(powerOfThree), mc); - result = result.subtract(logThree(mcDouble).multiply(valueOf(-factorOfThree), mc)); - } - - if (x == correctedX && result == ZERO) { - return logUsingNewton(x, mathContext); - } - - result = result.add(logUsingNewton(correctedX, mc), mc); - - return result; - } - - /** - * Returns the number pi. - * - *

See Wikipedia: Pi

- * - * @param mathContext the {@link MathContext} used for the result - * @return the number pi with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal pi(MathContext mathContext) { - checkMathContext(mathContext); - BigDecimal result = null; - - synchronized (piCacheLock) { - if (piCache != null && mathContext.getPrecision() <= piCache.precision()) { - result = piCache; - } else { - piCache = piChudnovski(mathContext); - return piCache; - } - } - - return round(result, mathContext); - } - - private static BigDecimal piChudnovski(MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 10, mathContext.getRoundingMode()); - - final BigDecimal value24 = BigDecimal.valueOf(24); - final BigDecimal value640320 = BigDecimal.valueOf(640320); - final BigDecimal value13591409 = BigDecimal.valueOf(13591409); - final BigDecimal value545140134 = BigDecimal.valueOf(545140134); - final BigDecimal valueDivisor = value640320.pow(3).divide(value24, mc); - - BigDecimal sumA = BigDecimal.ONE; - BigDecimal sumB = BigDecimal.ZERO; - - BigDecimal a = BigDecimal.ONE; - long dividendTerm1 = 5; // -(6*k - 5) - long dividendTerm2 = -1; // 2*k - 1 - long dividendTerm3 = -1; // 6*k - 1 - BigDecimal kPower3 = BigDecimal.ZERO; - - long iterationCount = (mc.getPrecision()+13) / 14; - for (long k = 1; k <= iterationCount; k++) { - BigDecimal valueK = BigDecimal.valueOf(k); - dividendTerm1 += -6; - dividendTerm2 += 2; - dividendTerm3 += 6; - BigDecimal dividend = BigDecimal.valueOf(dividendTerm1).multiply(BigDecimal.valueOf(dividendTerm2)).multiply(BigDecimal.valueOf(dividendTerm3)); - kPower3 = valueK.pow(3); - BigDecimal divisor = kPower3.multiply(valueDivisor, mc); - a = a.multiply(dividend).divide(divisor, mc); - BigDecimal b = valueK.multiply(a, mc); - - sumA = sumA.add(a); - sumB = sumB.add(b); - } - - final BigDecimal value426880 = BigDecimal.valueOf(426880); - final BigDecimal value10005 = BigDecimal.valueOf(10005); - final BigDecimal factor = value426880.multiply(sqrt(value10005, mc)); - BigDecimal pi = factor.divide(value13591409.multiply(sumA, mc).add(value545140134.multiply(sumB, mc)), mc); - - return round(pi, mathContext); - } - - /** - * Returns the number e. - * - *

See Wikipedia: E (mathematical_constant)

- * - * @param mathContext the {@link MathContext} used for the result - * @return the number e with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal e(MathContext mathContext) { - checkMathContext(mathContext); - BigDecimal result = null; - - synchronized (eCacheLock) { - if (eCache != null && mathContext.getPrecision() <= eCache.precision()) { - result = eCache; - } else { - eCache = exp(ONE, mathContext); - return eCache; - } - } - - return round(result, mathContext); - } - - private static BigDecimal logTen(MathContext mathContext) { - BigDecimal result = null; - - synchronized (log10CacheLock) { - if (log10Cache != null && mathContext.getPrecision() <= log10Cache.precision()) { - result = log10Cache; - } else { - log10Cache = logUsingNewton(BigDecimal.TEN, mathContext); - return log10Cache; - } - } - - return round(result, mathContext); - } - - private static BigDecimal logTwo(MathContext mathContext) { - BigDecimal result = null; - - synchronized (log2CacheLock) { - if (log2Cache != null && mathContext.getPrecision() <= log2Cache.precision()) { - result = log2Cache; - } else { - log2Cache = logUsingNewton(TWO, mathContext); - return log2Cache; - } - } - - return round(result, mathContext); - } - - private static BigDecimal logThree(MathContext mathContext) { - BigDecimal result = null; - - synchronized (log3CacheLock) { - if (log3Cache != null && mathContext.getPrecision() <= log3Cache.precision()) { - result = log3Cache; - } else { - log3Cache = logUsingNewton(THREE, mathContext); - return log3Cache; - } - } - - return round(result, mathContext); - } - - /** - * Calculates the natural exponent of {@link BigDecimal} x (ex). - * - *

See: Wikipedia: Exponent

- * - * @param x the {@link BigDecimal} to calculate the exponent for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated exponent {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal exp(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - if (x.signum() == 0) { - return ONE; - } - - return expIntegralFractional(x, mathContext); - } - - private static BigDecimal expIntegralFractional(BigDecimal x, MathContext mathContext) { - BigDecimal integralPart = integralPart(x); - - if (integralPart.signum() == 0) { - return expTaylor(x, mathContext); - } - - BigDecimal fractionalPart = x.subtract(integralPart); - - MathContext mc = new MathContext(mathContext.getPrecision() + 10, mathContext.getRoundingMode()); - - BigDecimal z = ONE.add(fractionalPart.divide(integralPart, mc)); - BigDecimal t = expTaylor(z, mc); - - BigDecimal result = pow(t, integralPart.intValueExact(), mc); - - return round(result, mathContext); - } - - private static BigDecimal expTaylor(BigDecimal x, MathContext mathContext) { - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - - x = x.divide(valueOf(256), mc); - - BigDecimal result = ExpCalculator.INSTANCE.calculate(x, mc); - result = BigDecimalMath.pow(result, 256, mc); - return round(result, mathContext); - } - - /** - * Calculates the sine (sinus) of {@link BigDecimal} x. - * - *

See: Wikipedia: Sine

- * - * @param x the {@link BigDecimal} to calculate the sine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated sine {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal sin(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - - if (x.abs().compareTo(ROUGHLY_TWO_PI) > 0) { - MathContext mc2 = new MathContext(mc.getPrecision() + 4, mathContext.getRoundingMode()); - BigDecimal twoPi = TWO.multiply(pi(mc2)); - x = x.remainder(twoPi, mc2); - } - - BigDecimal result = SinCalculator.INSTANCE.calculate(x, mc); - return round(result, mathContext); - } - - /** - * Calculates the arc sine (inverted sine) of {@link BigDecimal} x. - * - *

See: Wikipedia: Arcsine

- * - * @param x the {@link BigDecimal} to calculate the arc sine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc sine {@link BigDecimal} with the precision specified in the mathContext - * @throws ArithmeticException if x > 1 or x < -1 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal asin(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - if (x.compareTo(ONE) > 0) { - throw new ArithmeticException("Illegal asin(x) for x > 1: x = " + x); - } - if (x.compareTo(MINUS_ONE) < 0) { - throw new ArithmeticException("Illegal asin(x) for x < -1: x = " + x); - } - - if (x.signum() == -1) { - return asin(x.negate(), mathContext).negate(); - } - - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - - if (x.compareTo(BigDecimal.valueOf(0.707107)) >= 0) { - BigDecimal xTransformed = sqrt(ONE.subtract(x.multiply(x)), mc); - return acos(xTransformed, mathContext); - } - - BigDecimal result = AsinCalculator.INSTANCE.calculate(x, mc); - return round(result, mathContext); - } - - /** - * Calculates the cosine (cosinus) of {@link BigDecimal} x. - * - *

See: Wikipedia: Cosine

- * - * @param x the {@link BigDecimal} to calculate the cosine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated cosine {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal cos(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - - if (x.abs().compareTo(ROUGHLY_TWO_PI) > 0) { - MathContext mc2 = new MathContext(mc.getPrecision() + 4, mathContext.getRoundingMode()); - BigDecimal twoPi = TWO.multiply(pi(mc2), mc2); - x = x.remainder(twoPi, mc2); - } - - BigDecimal result = CosCalculator.INSTANCE.calculate(x, mc); - return round(result, mathContext); - } - - /** - * Calculates the arc cosine (inverted cosine) of {@link BigDecimal} x. - * - *

See: Wikipedia: Arccosine

- * - * @param x the {@link BigDecimal} to calculate the arc cosine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc sine {@link BigDecimal} with the precision specified in the mathContext - * @throws ArithmeticException if x > 1 or x < -1 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal acos(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - if (x.compareTo(ONE) > 0) { - throw new ArithmeticException("Illegal acos(x) for x > 1: x = " + x); - } - if (x.compareTo(MINUS_ONE) < 0) { - throw new ArithmeticException("Illegal acos(x) for x < -1: x = " + x); - } - - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - - BigDecimal result = pi(mc).divide(TWO, mc).subtract(asin(x, mc)); - return round(result, mathContext); - } - - /** - * Calculates the tangens of {@link BigDecimal} x. - * - *

See: Wikipedia: Tangens

- * - * @param x the {@link BigDecimal} to calculate the tangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated tangens {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal tan(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - if (x.signum() == 0) { - return ZERO; - } - - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - BigDecimal result = sin(x, mc).divide(cos(x, mc), mc); - return round(result, mathContext); - } - - /** - * Calculates the arc tangens (inverted tangens) of {@link BigDecimal} x. - * - *

See: Wikipedia: Arctangens

- * - * @param x the {@link BigDecimal} to calculate the arc tangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc tangens {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal atan(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - - x = x.divide(sqrt(ONE.add(x.multiply(x, mc)), mc), mc); - - BigDecimal result = asin(x, mc); - return round(result, mathContext); - } - - /** - * Calculates the arc tangens (inverted tangens) of {@link BigDecimal} y / x in the range -pi to pi. - * - *

This is useful to calculate the angle theta from the conversion of rectangular - * coordinates (xy) to polar coordinates (r, theta).

- * - *

See: Wikipedia: Atan2

- * - * @param y the {@link BigDecimal} - * @param x the {@link BigDecimal} - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc tangens {@link BigDecimal} with the precision specified in the mathContext - * @throws ArithmeticException if x = 0 and y = 0 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal atan2(BigDecimal y, BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 3, mathContext.getRoundingMode()); - - if (x.signum() > 0) { // x > 0 - return atan(y.divide(x, mc), mathContext); - } else if (x.signum() < 0) { - if (y.signum() > 0) { // x < 0 && y > 0 - return atan(y.divide(x, mc), mc).add(pi(mc), mathContext); - } else if (y.signum() < 0) { // x < 0 && y < 0 - return atan(y.divide(x, mc), mc).subtract(pi(mc), mathContext); - } else { // x < 0 && y = 0 - return pi(mathContext); - } - } else { - if (y.signum() > 0) { // x == 0 && y > 0 - return pi(mc).divide(TWO, mathContext); - } else if (y.signum() < 0) { // x == 0 && y < 0 - return pi(mc).divide(TWO, mathContext).negate(); - } else { - throw new ArithmeticException("Illegal atan2(y, x) for x = 0; y = 0"); - } - } - } - - /** - * Calculates the cotangens of {@link BigDecimal} x. - * - *

See: Wikipedia: Cotangens

- * - * @param x the {@link BigDecimal} to calculate the cotangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated cotanges {@link BigDecimal} with the precision specified in the mathContext - * @throws ArithmeticException if x = 0 - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal cot(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - if (x.signum() == 0) { - throw new ArithmeticException("Illegal cot(x) for x = 0"); - } - - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - BigDecimal result = cos(x, mc).divide(sin(x, mc), mc); - return round(result, mathContext); - } - - /** - * Calculates the inverse cotangens (arc cotangens) of {@link BigDecimal} x. - * - *

See: Wikipedia: Arccotangens

- * - * @param x the {@link BigDecimal} to calculate the arc cotangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc cotangens {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal acot(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - BigDecimal result = pi(mc).divide(TWO, mc).subtract(atan(x, mc)); - return round(result, mathContext); - } - - /** - * Calculates the hyperbolic sine of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the hyperbolic sine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated hyperbolic sine {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal sinh(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - BigDecimal result = SinhCalculator.INSTANCE.calculate(x, mc); - return round(result, mathContext); - } - - /** - * Calculates the hyperbolic cosine of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the hyperbolic cosine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated hyperbolic cosine {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal cosh(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); - BigDecimal result = CoshCalculator.INSTANCE.calculate(x, mc); - return round(result, mathContext); - } - - /** - * Calculates the hyperbolic tangens of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the hyperbolic tangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated hyperbolic tangens {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal tanh(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - BigDecimal result = sinh(x, mc).divide(cosh(x, mc), mc); - return round(result, mathContext); - } - - /** - * Calculates the hyperbolic cotangens of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the hyperbolic cotangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated hyperbolic cotangens {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal coth(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - BigDecimal result = cosh(x, mc).divide(sinh(x, mc), mc); - return round(result, mathContext); - } - - /** - * Calculates the arc hyperbolic sine (inverse hyperbolic sine) of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic sine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc hyperbolic sine {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal asinh(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 10, mathContext.getRoundingMode()); - BigDecimal result = log(x.add(sqrt(x.multiply(x, mc).add(ONE, mc), mc)), mc); - return round(result, mathContext); - } - - /** - * Calculates the arc hyperbolic cosine (inverse hyperbolic cosine) of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic cosine for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc hyperbolic cosine {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal acosh(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - BigDecimal result = log(x.add(sqrt(x.multiply(x).subtract(ONE), mc)), mc); - return round(result, mathContext); - } - - /** - * Calculates the arc hyperbolic tangens (inverse hyperbolic tangens) of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic tangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc hyperbolic tangens {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal atanh(BigDecimal x, MathContext mathContext) { - if (x.compareTo(BigDecimal.ONE) >= 0) { - throw new ArithmeticException("Illegal atanh(x) for x >= 1: x = " + x); - } - if (x.compareTo(MINUS_ONE) <= 0) { - throw new ArithmeticException("Illegal atanh(x) for x <= -1: x = " + x); - } - - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - BigDecimal result = log(ONE.add(x).divide(ONE.subtract(x), mc), mc).multiply(ONE_HALF); - return round(result, mathContext); - } - - /** - * Calculates the arc hyperbolic cotangens (inverse hyperbolic cotangens) of {@link BigDecimal} x. - * - *

See: Wikipedia: Hyperbolic function

- * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic cotangens for - * @param mathContext the {@link MathContext} used for the result - * @return the calculated arc hyperbolic cotangens {@link BigDecimal} with the precision specified in the mathContext - * @throws UnsupportedOperationException if the {@link MathContext} has unlimited precision - */ - public static BigDecimal acoth(BigDecimal x, MathContext mathContext) { - checkMathContext(mathContext); - MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); - BigDecimal result = log(x.add(ONE).divide(x.subtract(ONE), mc), mc).multiply(ONE_HALF); - return round(result, mathContext); - } - - private static void checkMathContext (MathContext mathContext) { - if (mathContext.getPrecision() == 0) { - throw new UnsupportedOperationException("Unlimited MathContext not supported"); - } - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/BigFloat.java b/src/main/java/ch/obermuhlner/math/big/BigFloat.java deleted file mode 100644 index eb8944f2c4..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/BigFloat.java +++ /dev/null @@ -1,1947 +0,0 @@ -package ch.obermuhlner.math.big; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.math.MathContext; -import java.math.RoundingMode; -import java.util.Objects; - -/** - * A wrapper around {@link BigDecimal} which simplifies the consistent usage of the {@link MathContext} - * and provides a simpler API for calculations. - * - *

Overview

- * - *

Every {@link BigFloat} instance has a reference to a {@link Context} that specifies the {@link MathContext} to be used for all calculations and values.

- * - *

The API for calculations is simplified and more consistent with the typical mathematical usage.

- *
    - *
  • Factory methods for values: - *
      - *
    • valueOf(BigFloat)
    • - *
    • valueOf(BigDecimal)
    • - *
    • valueOf(int)
    • - *
    • valueOf(long)
    • - *
    • valueOf(double)
    • - *
    • valueOf(String)
    • - *
    • pi()
    • - *
    • e()
    • - *
    - *
  • - *
  • All standard operators: - *
      - *
    • add(x)
    • - *
    • subtract(x)
    • - *
    • multiply(x)
    • - *
    • remainder(x)
    • - *
    • pow(y)
    • - *
    • root(y)
    • - *
    - *
  • - *
  • Calculation methods are overloaded for different value types: - *
      - *
    • add(BigFloat)
    • - *
    • add(BigDecimal)
    • - *
    • add(int)
    • - *
    • add(long)
    • - *
    • add(double)
    • - *
    • ...
    • - *
    - *
  • - *
  • Mathematical functions are written as they are traditionally are written: - *
      - *
    • abs(x)
    • - *
    • log(x)
    • - *
    • sin(x)
    • - *
    • min(x1, x2, ...)
    • - *
    • max(x1, x2, ...)
    • - *
    • ...
    • - *
    - *
  • - *
  • Support for advanced mathematical functions: - *
      - *
    • sqrt(x)
    • - *
    • log(x)
    • - *
    • exp(x)
    • - *
    • sin(x)
    • - *
    • cos(x)
    • - *
    • tan(x)
    • - *
    • ...
    • - *
    - *
  • - *
  • Methods to access parts of a value: - *
      - *
    • getMantissa()
    • - *
    • getExponent()
    • - *
    • getIntegralPart()
    • - *
    • getFractionalPart()
    • - *
    - *
  • - *
  • Equals and Hashcode methods: - *
      - *
    • equals(Object) that returns whether two BigFloat values are mathematically the same
    • - *
    • hashCode() consistent with equals(Object)
    • - *
    - *
  • - *
  • Comparison methods: - *
      - *
    • isEqual(BigFloat)
    • - *
    • isLessThan(BigFloat)
    • - *
    • isLessThanOrEqual(BigFloat)
    • - *
    • isGreaterThan(BigFloat)
    • - *
    • isGreaterThanOrEqual(BigFloat)
    • - *
    - *
  • - *
- * - *

Usage

- * - *

Before doing any calculations you need to create a Context specifying the precision used for all calculations.

- *
- * Context context = BigFloat.context(100); // precision of 100 digits
- * Context anotherContext = BigFloat.context(new MathContext(10, RoundingMode.HALF_UP); // precision of 10 digits, rounding half up
- * 
- * - *

The Context can then be used to create the first value of the calculation:

- *
- * BigFloat value1 = context.valueOf(640320);
- * 
- * - *

The BigFloat instance holds a reference to the Context. This context is then passed from calculation to calculation.

- *
- * BigFloat value2 = context.valueOf(640320).pow(3).divide(24);
- * BigFloat value3 = BigFloat.sin(value2);
- * 
- * - *

The BigFloat result can be converted to other numerical types:

- *
- * BigDecimal bigDecimalValue = value3.toBigDecimal();
- * double doubleValue = value3.toDouble();
- * long longValue = value3.toLong();
- * int intValue = value3.toInt();
- * 
- */ -@SuppressWarnings("WeakerAccess") -public class BigFloat implements Comparable, Serializable { - private static final long serialVersionUID = -7323679117445486894L; - - /** - * Represents a value that is not a number. - * @see Double#NaN - */ - public static final BigFloat NaN = new SpecialBigFloat(SpecialBigFloat.Type.NaN); - - /** - * Represents the positive infinity. - * @see Double#POSITIVE_INFINITY - */ - public static final BigFloat POSITIVE_INFINITY = new SpecialBigFloat(SpecialBigFloat.Type.POSITIVE_INFINITY); - - /** - * Represents the positive infinity. - * @see Double#NEGATIVE_INFINITY - */ - public static final BigFloat NEGATIVE_INFINITY = new SpecialBigFloat(SpecialBigFloat.Type.NEGATIVE_INFINITY); - - private final BigDecimal value; - private final Context context; - - private BigFloat(BigDecimal value, Context context) { - this.value = value; - this.context = context; - } - - /** - * Creates a {@link Context} with the specified precision and {@link RoundingMode#HALF_UP} rounding. - * - * @param precision the precision - * - * @return the {@link Context} - */ - public static Context context(int precision) { - return new Context(new MathContext(precision)); - } - - /** - * Creates a {@link Context} with the specified {@link MathContext}. - * - * @param mathContext the {@link MathContext} - * - * @return the {@link Context} - */ - public static Context context(MathContext mathContext) { - return new Context(mathContext); - } - - /** - * Returns the {@link BigFloat} that is this + x. - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param x the value to add - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#add(BigDecimal, MathContext) - */ - public BigFloat add(BigFloat x) { - if (x.isSpecial()) - return x.add(this); - Context c = max(context, x.context); - return c.valueOf(value.add(x.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is this + x. - * - * @param x the value to add - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#add(BigDecimal, MathContext) - */ - public BigFloat add(BigDecimal x) { - return add(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this + x. - * - * @param x the value to add - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#add(BigDecimal, MathContext) - */ - public BigFloat add(int x) { - return add(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this + x. - * - * @param x the value to add - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#add(BigDecimal, MathContext) - */ - public BigFloat add(long x) { - return add(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this + x. - * - * @param x the value to add - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#add(BigDecimal, MathContext) - */ - public BigFloat add(double x) { - return add(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this - x. - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param x the value to subtract - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#subtract(BigDecimal, MathContext) - */ - public BigFloat subtract(BigFloat x) { - if (x.isSpecial()) - return negate(x).add(this); - Context c = max(context, x.context); - return c.valueOf(value.subtract(x.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is this - x. - * - * @param x the value to subtract - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#subtract(BigDecimal, MathContext) - */ - public BigFloat subtract(BigDecimal x) { - return subtract(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this - x. - * - * @param x the value to subtract - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#subtract(BigDecimal, MathContext) - */ - public BigFloat subtract(int x) { - return subtract(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this - x. - * - * @param x the value to subtract - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#subtract(BigDecimal, MathContext) - */ - public BigFloat subtract(long x) { - return subtract(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this - x. - * - * @param x the value to subtract - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#subtract(BigDecimal, MathContext) - */ - public BigFloat subtract(double x) { - return subtract(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this * x. - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param x the value to multiply - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#multiply(BigDecimal, MathContext) - */ - public BigFloat multiply(BigFloat x) { - if (x.isSpecial()) - return x.multiply(this); - Context c = max(context, x.context); - return c.valueOf(value.multiply(x.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is this * x. - * - * @param x the value to multiply - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#multiply(BigDecimal, MathContext) - */ - public BigFloat multiply(BigDecimal x) { - return multiply(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this * x. - * - * @param x the value to multiply - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#multiply(BigDecimal, MathContext) - */ - public BigFloat multiply(int x) { - return multiply(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this * x. - * - * @param x the value to multiply - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#multiply(BigDecimal, MathContext) - */ - public BigFloat multiply(long x) { - return multiply(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this * x. - * - * @param x the value to multiply - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#multiply(BigDecimal, MathContext) - */ - public BigFloat multiply(double x) { - return multiply(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this / x. - * - *

If the two values do not have the same {@link Context}, - * the result will contain the {@link Context} with the larger precision.

- * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#divide(BigDecimal, MathContext) - */ - public BigFloat divide(BigFloat x) { - if (x.isSpecial()) { - if (x == NaN) { - return NaN; - } else { - return context.valueOf(0); - } - } - if (this.isZero() && !x.isZero()) { - return context.valueOf(0); - } - if (x.isZero()) { - if (this.isZero()) { - return NaN; // 0 or -0 / 0 = NaN - } else if (this.isNegative()) { - return NEGATIVE_INFINITY;// -N / 0 = -INF - } else { - return POSITIVE_INFINITY;// N / 0 = +INF - } - } - - Context c = max(context, x.context); - return c.valueOf(value.divide(x.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is this / x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#divide(BigDecimal, MathContext) - */ - public BigFloat divide(BigDecimal x) { - return divide(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this / x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#divide(BigDecimal, MathContext) - */ - public BigFloat divide(int x) { - return divide(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this / x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#divide(BigDecimal, MathContext) - */ - public BigFloat divide(long x) { - return divide(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this / x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#divide(BigDecimal, MathContext) - */ - public BigFloat divide(double x) { - return divide(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is the remainder when dividing this by x. - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#remainder(BigDecimal, MathContext) - */ - public BigFloat remainder(BigFloat x) { - if (x.isSpecial()) { - if (x == NaN) { - return NaN; - } else { - return this; - } - } - if (this.isZero() && !x.isZero()) { - return context.valueOf(0); - } - if (x.isZero()) { - return NaN; - } - - Context c = max(context, x.context); - return c.valueOf(value.remainder(x.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is the remainder when dividing this by x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#remainder(BigDecimal, MathContext) - */ - public BigFloat remainder(BigDecimal x) { - return remainder(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is the remainder when dividing this by x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#remainder(BigDecimal, MathContext) - */ - public BigFloat remainder(int x) { - return remainder(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is the remainder when dividing this by x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#remainder(BigDecimal, MathContext) - */ - public BigFloat remainder(long x) { - return remainder(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is the remainder when dividing this by x. - * - * @param x the value to divide with - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#remainder(BigDecimal, MathContext) - */ - public BigFloat remainder(double x) { - return remainder(context.valueOf(x)); - } - - /** - * Returns the {@link BigFloat} that is this to the power of y. - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param y the value of the power - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat pow(BigFloat y) { - if (y.isSpecial()) { - if (this.isZero()) { - if (y == POSITIVE_INFINITY) { - return this; - } - if (y == NEGATIVE_INFINITY) { - return POSITIVE_INFINITY; - } - } - if (y == NEGATIVE_INFINITY) { - return context.ZERO; - } - return y; - } - if (this.isZero()) { - if (y.isNegative()) { - return POSITIVE_INFINITY; - } - } - - Context c = max(context, y.context); - return c.valueOf(BigDecimalMath.pow(this.value, y.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is this to the power of y. - * - * @param y the value of the power - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat pow(BigDecimal y) { - return pow(context.valueOf(y)); - } - - /** - * Returns the {@link BigFloat} that is this to the power of y. - * - * @param y the value of the power - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat pow(int y) { - return pow(context.valueOf(y)); - } - - /** - * Returns the {@link BigFloat} that is this to the power of y. - * - * @param y the value of the power - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat pow(long y) { - return pow(context.valueOf(y)); - } - - /** - * Returns the {@link BigFloat} that is this to the power of y. - * - * @param y the value of the power - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat pow(double y) { - return pow(context.valueOf(y)); - } - - /** - * Returns the {@link BigFloat} that is the yth root of this. - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param y the value of the root - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat root(BigFloat y) { - if (y.isSpecial()) - return y; - Context c = max(context, y.context); - return c.valueOf(BigDecimalMath.root(this.value, y.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is the yth root of this. - * - * @param y the value of the root - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat root(BigDecimal y) { - return root(context.valueOf(y)); - } - - /** - * Returns the {@link BigFloat} that is the yth root of this. - * - * @param y the value of the root - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat root(int y) { - return root(context.valueOf(y)); - } - - /** - * Returns the {@link BigFloat} that is the yth root of this. - * - * @param y the value of the root - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat root(long y) { - return root(context.valueOf(y)); - } - - /** - * Returns the {@link BigFloat} that is the yth root of this. - * - * @param y the value of the root - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) - */ - public BigFloat root(double y) { - return root(context.valueOf(y)); - } - - @Override - public int hashCode() { - return value.stripTrailingZeros().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - BigFloat other = (BigFloat) obj; - - return value.compareTo(other.value) == 0; - //return Objects.equals(value, other.value) && Objects.equals(context, other.context); - } - - /** - * Returns the signum function of this {@link BigFloat}. - * - * @return -1, 0, or 1 as the value of this {@link BigDecimal} is negative, zero, or positive. - */ - public int signum() { - return value.signum(); - } - - /** - * Returns whether this {@link BigFloat} is negative. - * - * @return true if negative, false if 0 or positive - */ - public boolean isNegative() { - return value.signum() < 0; - } - - /** - * Returns whether this {@link BigFloat} is 0. - * - * @return true if 0, false if negative or positive - */ - public boolean isZero() { - return value.signum() == 0; - } - - /** - * Returns whether this {@link BigFloat} is positive. - * - * @return true if positive, false if 0 or negative - */ - public boolean isPositive() { - return value.signum() > 0; - } - - @Override - public int compareTo(BigFloat other) { - if (other.isSpecial()) { - return -other.compareTo(this); - } - return value.compareTo(other.value); - } - - /** - * Returns whether this value is mathematically equal to the other value. - * - * @param other the other {@link BigFloat} to compare with - * - * @return true if both values are mathematically equal (equivalent to this.compareTo(other) == 0 - * - * @see #compareTo(BigFloat) - */ - public boolean isEqual(BigFloat other) { - if (this == NaN || other == NaN) { - return false; - } - - return compareTo(other) == 0; - } - - /** - * Returns whether this value is mathematically less than to the other value. - * - * @param other the other {@link BigFloat} to compare with - * - * @return true this value is mathematically less than to the other value (equivalent to this.compareTo(other) < 0 - * - * @see #compareTo(BigFloat) - */ - public boolean isLessThan(BigFloat other) { - if (this == NaN || other == NaN) { - return false; - } - - return compareTo(other) < 0; - } - - /** - * Returns whether this value is mathematically greater than to the other value. - * - * @param other the other {@link BigFloat} to compare with - * - * @return true this value is mathematically greater than to the other value (equivalent to this.compareTo(other) > 0 - * - * @see #compareTo(BigFloat) - */ - public boolean isGreaterThan(BigFloat other) { - if (this == NaN || other == NaN) { - return false; - } - - return compareTo(other) > 0; - } - - /** - * Returns whether this value is mathematically less than or equal to the other value. - * - * @param other the other {@link BigFloat} to compare with - * - * @return true this value is mathematically less than or equal to the other value (equivalent to this.compareTo(other) <= 0 - * - * @see #compareTo(BigFloat) - * @see #isLessThan(BigFloat) - * @see #isEqual(BigFloat) - */ - public boolean isLessThanOrEqual(BigFloat other) { - if (this == NaN || other == NaN) { - return false; - } - - return compareTo(other) <= 0; - } - - /** - * Returns whether this value is mathematically greater than or equal to the other value. - * - * @param other the other {@link BigFloat} to compare with - * - * @return true this value is mathematically greater than or equal to the other value (equivalent to this.compareTo(other) >= 0 - * - * @see #compareTo(BigFloat) - * @see #isGreaterThan(BigFloat) - * @see #isEqual(BigFloat) - */ - public boolean isGreaterThanOrEqual(BigFloat other) { - if (this == NaN || other == NaN) { - return false; - } - - return compareTo(other) >= 0; - } - - /** - * Returns whether this value can be represented as int. - * - * @return true if the value can be represented as int value - * - * @see BigDecimalMath#isIntValue(BigDecimal) - */ - public boolean isIntValue() { - return BigDecimalMath.isIntValue(value); - } - - /** - * Returns whether this specified {@link BigDecimal} value can be represented as double. - * - * @return true if the value can be represented as double value - * - * @see BigDecimalMath#isDoubleValue(BigDecimal) - */ - public boolean isDoubleValue() { - return BigDecimalMath.isDoubleValue(value); - } - - /** - * Returns the mantissa of this value written as mantissa * 10exponent. - * - *

The mantissa is defined as having exactly 1 digit before the decimal point.

- * - * @return the mantissa - * - * @see #getExponent() - * @see BigDecimalMath#mantissa(BigDecimal) - */ - public BigFloat getMantissa() { - return context.valueOf(BigDecimalMath.mantissa(value)); - } - - /** - * Returns the exponent of this value written as mantissa * 10exponent. - * - *

The mantissa is defined as having exactly 1 digit before the decimal point.

- * - * @return the exponent - * - * @see #getMantissa() - * @see BigDecimalMath#exponent(BigDecimal) - */ - public BigFloat getExponent() { - return context.valueOf(BigDecimalMath.exponent(value)); - } - - /** - * Returns the integral part of this value (left of the decimal point). - * - * @return the integral part - * - * @see #getFractionalPart() - * @see BigDecimalMath#fractionalPart(BigDecimal) - */ - public BigFloat getIntegralPart() { - return context.valueOf(BigDecimalMath.integralPart(value)); - } - - /** - * Returns the fractional part of this value (right of the decimal point). - * - * @return the fractional part - * - * @see #getIntegralPart() - * @see BigDecimalMath#fractionalPart(BigDecimal) - */ - public BigFloat getFractionalPart() { - return context.valueOf(BigDecimalMath.fractionalPart(value)); - } - - /** - * Returns the {@link Context} of this value. - * - * @return the {@link Context} - */ - public Context getContext() { - return context; - } - - /** - * Returns this value as a {@link BigDecimal} value. - * - * @return the {@link BigDecimal} value - */ - public BigDecimal toBigDecimal() { - return value; - } - - /** - * Returns this value as a double value. - * - * @return the double value - * - * @see BigDecimal#doubleValue() - */ - public double toDouble() { - return value.doubleValue(); - } - - /** - * Returns this value as a long value. - * - * @return the long value - * - * @see BigDecimal#longValue() - */ - public long toLong() { - return value.longValue(); - } - - /** - * Returns this value as a int value. - * - * @return the int value - * - * @see BigDecimal#intValue() - */ - public int toInt() { - return value.intValue(); - } - - @Override - public String toString() { - return value.toString(); - } - - protected boolean isSpecial() { - return false; - } - - /** - * return special type of a value - * @return {@link SpecialBigFloat.Type} - */ - protected SpecialBigFloat.Type type() { - return SpecialBigFloat.Type.NORMAL; - } - - public boolean isNaN() { - return this == NaN; - } - - public boolean isInfinity() { - return this == POSITIVE_INFINITY || this == NEGATIVE_INFINITY; - } - - /** - * this class handle unrepresentable value in floating-point arithmetic - * - * @author Wireless4024 - */ - private static final class SpecialBigFloat extends BigFloat { - - private static final Context DUMMY_CONTEXT = BigFloat.context(MathContext.DECIMAL32); - - private final Type type; - - private SpecialBigFloat(Type type) { - super(null, DUMMY_CONTEXT); - this.type = type; - } - - @Override - protected boolean isSpecial() { - return true; - } - - @Override - protected Type type() { - return type; - } - - @Override - public BigFloat add(BigFloat x) { - if (!x.isSpecial()) { - return this; - } - if (this == POSITIVE_INFINITY && x == POSITIVE_INFINITY) { - return POSITIVE_INFINITY; - } - if (this == NEGATIVE_INFINITY && x == NEGATIVE_INFINITY) { - return NEGATIVE_INFINITY; - } - return NaN; - } - - @Override - public BigFloat subtract(BigFloat x) { - if (!x.isSpecial()) { - return this; - } - if (this == POSITIVE_INFINITY && x == NEGATIVE_INFINITY) { - return POSITIVE_INFINITY; - } - if (this == NEGATIVE_INFINITY && x == POSITIVE_INFINITY) { - return NEGATIVE_INFINITY; - } - return NaN; - } - - @Override - public BigFloat subtract(BigDecimal x) { - return this; - } - - @Override - public BigFloat multiply(BigFloat x) { - if (x.isZero() || x == NaN) { - return NaN; - } else if (x.isNegative()) { - return negate(this); - } else { - return this; - } - } - - @Override - public BigFloat divide(BigFloat x) { - if (x == NaN || (this.isInfinity() && x.isInfinity())) { - return NaN; - } else if (x.isNegative()) { - return negate(this); - } else { - return this; - } - } - - @Override - public BigFloat remainder(BigFloat x) { - return NaN; - } - - @Override - public BigFloat pow(BigFloat y) { - if (y.isZero()) { - return y.context.ONE; - } - if (y == NaN) { - return NaN; - } - if (this.isInfinity() && y.isNegative()) { - return y.context.ZERO; - } - if (this == NEGATIVE_INFINITY && y.isPositive()) { - return POSITIVE_INFINITY; - } - return this; - } - - @Override - public BigFloat root(BigFloat y) { - return this; - } - - @Override - public int hashCode() { - return type.hashCode; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - return obj instanceof BigFloat && ((BigFloat) obj).isSpecial() && ((BigFloat) obj).type() == this.type; - } - - @Override - public int signum() { - return type == Type.POSITIVE_INFINITY ? 1 : -1; - } - - @Override - public boolean isNegative() { - return signum() < 0; - } - - @Override - public boolean isZero() { - return false;//nan or infinity is not a zero - } - - @Override - public boolean isPositive() { - return signum() > 0; - } - - @Override - public int compareTo(BigFloat other) { - return Type.compare(type, other.type()); - } - - @Override - public boolean isIntValue() { - return false; - } - - @Override - public boolean isDoubleValue() { - return false; - } - - @Override - public BigFloat getMantissa() { - return this; - } - - @Override - public BigFloat getExponent() { - return this; - } - - @Override - public BigFloat getIntegralPart() { - return this; - } - - @Override - public BigFloat getFractionalPart() { - return this; - } - - @Override - public Context getContext() { - throw new UnsupportedOperationException(type + " has no context"); - } - - @Override - public BigDecimal toBigDecimal() { - throw new UnsupportedOperationException(type + " has no corresponding BigDecimal representation"); - } - - @Override - public double toDouble() { - return type.toDouble(); - } - - @Override - public long toLong() { - return (long) toDouble(); - } - - @Override - public int toInt() { - return (int) toDouble(); - } - - @Override - public String toString() { - return type.toString(); - } - - //optional static - enum Type { - NaN(Objects.hashCode(Double.NaN)), - POSITIVE_INFINITY(Objects.hashCode(Double.POSITIVE_INFINITY)), - NORMAL(Objects.hashCode(0)), - NEGATIVE_INFINITY(Objects.hashCode(Double.NEGATIVE_INFINITY)); - - final int hashCode; - - Type(int hashCode){ - this.hashCode=hashCode; - } - - public static int compare(Type a, Type b) { - //we can use double to compare - //if (a == NaN && b == NaN) - // return 0;//cuz NaN equals nothing even itself - return Double.compare(a.toDouble(),b.toDouble()); - } - - /** - * convert type to double - * @return double value that equivalent to {@link Type} - */ - public double toDouble() { - switch (this) { - case POSITIVE_INFINITY: - return Double.POSITIVE_INFINITY; - case NEGATIVE_INFINITY: - return Double.NEGATIVE_INFINITY; - case NaN: - return Double.NaN; - default: - return 0; - } - } - } - } - - /** - * Manages the {@link MathContext} and provides factory methods for {@link BigFloat} values. - */ - public static class Context implements Serializable{ - private static final long serialVersionUID = -5787473786808803161L; - public final BigFloat NEGATIVE_ONE; - public final BigFloat ZERO; - public final BigFloat ONE; - - private final MathContext mathContext; - - private Context(MathContext mathContext) { - this.mathContext = mathContext; - NEGATIVE_ONE = this.valueOf(-1); - ZERO = this.valueOf(0); - ONE = this.valueOf(1); - } - - /** - * Returns the {@link MathContext} of this context. - * - * @return the {@link MathContext} - */ - public MathContext getMathContext() { - return mathContext; - } - - /** - * Returns the precision of this context. - *

- * This is equivalent to calling getMathContext().getPrecision(). - * - * @return the precision - */ - public int getPrecision() { - return mathContext.getPrecision(); - } - - /** - * Returns the {@link RoundingMode} of this context. - *

- * This is equivalent to calling getMathContext().getRoundingMode(). - * - * @return the {@link RoundingMode} - */ - public RoundingMode getRoundingMode() { - return mathContext.getRoundingMode(); - } - - /** - * Creates a {@link BigFloat} value with this context. - * - * @param value the source {@link BigFloat} value - * - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - */ - public BigFloat valueOf(BigFloat value) { - return value.isSpecial() ? value : new BigFloat(value.value.round(mathContext), this);//they are final - } - - /** - * Creates a {@link BigFloat} value with this context. - * - * @param value the source {@link BigDecimal} value - * - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - */ - public BigFloat valueOf(BigDecimal value) { - return new BigFloat(value.round(mathContext), this); - } - - /** - * Creates a {@link BigFloat} value with this context. - * - * @param value the source int value - * - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - */ - public BigFloat valueOf(int value) { - return new BigFloat(new BigDecimal(value, mathContext), this); - } - - /** - * parse unsigned value with this logic

value & 4294967295
- * @param value an int value - * @param unsigned if true value will parse as unsigned integer - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - */ - public BigFloat valueOf(int value, boolean unsigned) { - if (!unsigned) { - return new BigFloat(new BigDecimal(value, mathContext), this); - } else { - if (value > -1) - return valueOf(value, false); - return new BigFloat(new BigDecimal(Integer.MAX_VALUE) - .add(new BigDecimal(value & Integer.MAX_VALUE)) - .add(BigDecimal.ONE), this); - } - } - - /** - * Creates a {@link BigFloat} value with this context. - * - * @param value the source long value - * - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - */ - public BigFloat valueOf(long value) { - return new BigFloat(new BigDecimal(value, mathContext), this); - } - - /** - * parse unsigned value with this logic
value & 18446744073709551615
- * @param value an int value - * @param unsigned if true value will parse as unsigned integer - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - */ - public BigFloat valueOf(long value, boolean unsigned) { - if (!unsigned) { - return new BigFloat(new BigDecimal(value, mathContext), this); - } else { - if (value > -1) - return valueOf(value, false); - return new BigFloat(new BigDecimal(Long.MAX_VALUE) - .add(new BigDecimal(value & Long.MAX_VALUE)) - .add(BigDecimal.ONE), this); - } - } - - /** - * Creates a {@link BigFloat} value with this context. - * - * @param value the source double value - * - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - */ - public BigFloat valueOf(double value) { - if (Double.isInfinite(value)) - return value == Double.POSITIVE_INFINITY ? POSITIVE_INFINITY : NEGATIVE_INFINITY; - else if (Double.isNaN(value)) - return NaN; - return new BigFloat(new BigDecimal(String.valueOf(value), mathContext), this); - } - - /** - * Creates a {@link BigFloat} value with this context. - * - * @param value the source String value - * - * @return the {@link BigFloat} value with this context (rounded to the precision of this context) - * - * @throws NumberFormatException if the value is not a valid number. - */ - public BigFloat valueOf(String value) { - return new BigFloat(new BigDecimal(value, mathContext), this); - } - - /** - * Returns the constant pi with this context. - * - * @return pi with this context (rounded to the precision of this context) - * - * @see BigDecimalMath#pi(MathContext) - */ - public BigFloat pi() { - return valueOf(BigDecimalMath.pi(mathContext)); - } - - /** - * Returns the constant e with this context. - * - * @return e with this context (rounded to the precision of this context) - * - * @see BigDecimalMath#e(MathContext) - */ - public BigFloat e() { - return valueOf(BigDecimalMath.e(mathContext)); - } - - /** - * Returns the factorial of n with this context. - * - * @param n the value to calculate - * - * @return the factorial of n with this context (rounded to the precision of this context) - * - * @see BigDecimalMath#factorial(int) - */ - public BigFloat factorial(int n) { - return valueOf(BigDecimalMath.factorial(n)); - } - - @Override - public int hashCode() { - return mathContext.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Context other = (Context) obj; - return mathContext.equals(other.mathContext); - } - - @Override - public String toString() { - return mathContext.toString(); - } - } - /** - * Returns the {@link BigFloat} that is - this. - * - * @param x the value to negate - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#negate(MathContext) - */ - public static BigFloat negate(BigFloat x) { - if (x.isSpecial()) - if (x.isInfinity()) - return x == POSITIVE_INFINITY ? NEGATIVE_INFINITY : POSITIVE_INFINITY; - else - return NaN; - return x.context.valueOf(x.value.negate()); - } - - /** - * Returns the {@link BigFloat} that is the abs(this) (absolute value). - * - * @param x the value to make absolute - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimal#abs(MathContext) - */ - public static BigFloat abs(BigFloat x) { - if (x.isSpecial()) - return x.isInfinity() ? POSITIVE_INFINITY : NaN; - return x.context.valueOf(x.value.abs()); - } - - /** - * Returns the the maximum of two {@link BigFloat} values. - * - * @param value1 the first {@link BigFloat} value to compare - * @param value2 the second {@link BigFloat} value to compare - * - * @return the maximum {@link BigFloat} value - */ - public static BigFloat max(BigFloat value1, BigFloat value2) { - return value1.compareTo(value2) >= 0 ? value1 : value2; - } - - /** - * Returns the the maximum of n {@link BigFloat} values. - * - * @param value1 the first {@link BigFloat} value to compare - * @param values the other {@link BigFloat}s value to compare - * - * @return the maximum {@link BigFloat} value - */ - public static BigFloat max(BigFloat value1, BigFloat... values) { - BigFloat result = value1; - - for (BigFloat other : values) { - result = max(result, other); - } - - return result; - } - - /** - * Returns the the minimum of two {@link BigFloat} values. - * - * @param value1 the first {@link BigFloat} value to compare - * @param value2 the second {@link BigFloat} value to compare - * - * @return the minimum {@link BigFloat} value - */ - public static BigFloat min(BigFloat value1, BigFloat value2) { - return value1.compareTo(value2) < 0 ? value1 : value2; - } - - /** - * Returns the the minimum of n {@link BigFloat} values. - * - * @param value1 the first {@link BigFloat} value to compare - * @param values the other {@link BigFloat}s value to compare - * - * @return the minimum {@link BigFloat} value - */ - public static BigFloat min(BigFloat value1, BigFloat... values) { - BigFloat result = value1; - - for (BigFloat other : values) { - result = min(result, other); - } - - return result; - } - - private static BigFloat logSpecial(BigFloat val){ - if (val.isNaN() || val.isNegative()) - return NaN; - if (val == POSITIVE_INFINITY) - return POSITIVE_INFINITY; - if (val.isZero()) - return NEGATIVE_INFINITY; - return null; - } - - /** - * Returns the {@link BigFloat} that is log(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#log(BigDecimal, MathContext) - */ - public static BigFloat log(BigFloat x) { - BigFloat temp = logSpecial(x); - return temp != null ? temp : x.context.valueOf(BigDecimalMath.log(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is log2(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#log2(BigDecimal, MathContext) - */ - public static BigFloat log2(BigFloat x) { - BigFloat temp = logSpecial(x); - return temp != null ? temp : x.context.valueOf(BigDecimalMath.log2(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is log10(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#log10(BigDecimal, MathContext) - */ - public static BigFloat log10(BigFloat x) { - BigFloat temp = logSpecial(x); - return temp != null ? temp : x.context.valueOf(BigDecimalMath.log10(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is exp(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#exp(BigDecimal, MathContext) - */ - public static BigFloat exp(BigFloat x) { - if(x.isSpecial()) - return x != NEGATIVE_INFINITY ? x : x.context.ZERO; - return x.context.valueOf(BigDecimalMath.exp(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is sqrt(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#sqrt(BigDecimal, MathContext) - */ - public static BigFloat sqrt(BigFloat x) { - if (x.isNaN() || x.isNegative()) - return NaN; - if (x.isZero() || x.isInfinity()) - return x; - return x.context.valueOf(BigDecimalMath.sqrt(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is pow(x, y). - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param x the {@link BigFloat} value to take to the power - * @param y the {@link BigFloat} value to serve as exponent - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public static BigFloat pow(BigFloat x, BigFloat y) { - Context c = max(x.context, y.context); - return c.valueOf(BigDecimalMath.pow(x.value, y.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is root(x, y). - * - *

If the two values do not have the same {@link Context}, the result will contain the {@link Context} with the larger precision.

- * - * @param x the {@link BigFloat} value to calculate the n'th root - * @param y the {@link BigFloat} defining the root - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public static BigFloat root(BigFloat x, BigFloat y) { - Context c = max(x.context, y.context); - return c.valueOf(BigDecimalMath.root(x.value, y.value, c.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is sin(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#sin(BigDecimal, MathContext) - */ - public static BigFloat sin(BigFloat x) { - if(x.isSpecial()) - return NaN; - if(x.isZero()) - return x; - return x.context.valueOf(BigDecimalMath.sin(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is cos(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#cos(BigDecimal, MathContext) - */ - public static BigFloat cos(BigFloat x) { - if(x.isSpecial()) - return NaN; - return x.context.valueOf(BigDecimalMath.cos(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is tan(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#tan(BigDecimal, MathContext) - */ - public static BigFloat tan(BigFloat x) { - if(x.isSpecial()) - return NaN; - if(x.isZero()) - return x; - return x.context.valueOf(BigDecimalMath.tan(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is cot(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#cot(BigDecimal, MathContext) - */ - public static BigFloat cot(BigFloat x) { - if(x.isSpecial()) - return x; - if(x.isZero()) - return POSITIVE_INFINITY; - return x.context.valueOf(BigDecimalMath.cot(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is asin(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#asin(BigDecimal, MathContext) - */ - public static BigFloat asin(BigFloat x) { - if (x.isZero()) - return x; - return x.isNaN() || (!isRangeAbs1(x)) ? NaN : - x.context.valueOf(BigDecimalMath.asin(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is acos(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#acos(BigDecimal, MathContext) - */ - public static BigFloat acos(BigFloat x) { - return x.isNaN() || (!isRangeAbs1(x)) ? NaN : - x.context.valueOf(BigDecimalMath.acos(x.value, x.context.mathContext)); - } - - /** - * @param x a bigfloat - * @return if abs(x) <= 1 - */ - private static boolean isRangeAbs1(BigFloat x) { - return isBetween(x.context.NEGATIVE_ONE, x.context.ONE, x); - } - - /** - * Returns the {@link BigFloat} that is atan(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#atan(BigDecimal, MathContext) - */ - public static BigFloat atan(BigFloat x) { - return x.isSpecial() || x.isZero() ? x : x.context.valueOf(BigDecimalMath.atan(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is acot(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#acot(BigDecimal, MathContext) - */ - public static BigFloat acot(BigFloat x) { - return x.isSpecial() ? x : x.context.valueOf(BigDecimalMath.acot(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is sinh(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#sinh(BigDecimal, MathContext) - */ - public static BigFloat sinh(BigFloat x) { - if (x.isSpecial() || x.isZero()) - return x; - return x.context.valueOf(BigDecimalMath.sinh(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is cosh(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#cosh(BigDecimal, MathContext) - */ - public static BigFloat cosh(BigFloat x) { - if (x.isNaN()) - return NaN; - if (x.isInfinity()) - return POSITIVE_INFINITY; - if (x.isZero()) - return x.context.ONE; - return x.context.valueOf(BigDecimalMath.cosh(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is tanh(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#tanh(BigDecimal, MathContext) - */ - public static BigFloat tanh(BigFloat x) { - if (x.isNaN() || x.isZero()) - return x; - if (x.isInfinity()) - return x == POSITIVE_INFINITY ? x.context.ONE : x.context.NEGATIVE_ONE; - return x.context.valueOf(BigDecimalMath.tanh(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is coth(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#coth(BigDecimal, MathContext) - */ - public static BigFloat coth(BigFloat x) { - if(x.isSpecial()) - return x; - return x.context.valueOf(BigDecimalMath.coth(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is asinh(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#asinh(BigDecimal, MathContext) - */ - public static BigFloat asinh(BigFloat x) { - if(x.isSpecial()) - return x; - return x.context.valueOf(BigDecimalMath.asinh(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is acosh(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#acosh(BigDecimal, MathContext) - */ - public static BigFloat acosh(BigFloat x) { - return x.context.valueOf(BigDecimalMath.acosh(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is atanh(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#atanh(BigDecimal, MathContext) - */ - public static BigFloat atanh(BigFloat x) { - if(x.isSpecial()) - return x; - return x.context.valueOf(BigDecimalMath.atanh(x.value, x.context.mathContext)); - } - - /** - * Returns the {@link BigFloat} that is acoth(x). - * - * @param x the value - * - * @return the resulting {@link BigFloat} - * - * @see BigDecimalMath#acoth(BigDecimal, MathContext) - */ - public static BigFloat acoth(BigFloat x) { - if(x.isSpecial()) - return x; - return x.context.valueOf(BigDecimalMath.acoth(x.value, x.context.mathContext)); - } - - public static boolean isBetween(BigFloat min, BigFloat max, BigFloat value) { - return value.compareTo(min) >= 0 && value.compareTo(max) <= 0; - } - - private static Context max(Context left, Context right) { - return left.mathContext.getPrecision() > right.mathContext.getPrecision() ? left : right; - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/BigRational.java b/src/main/java/ch/obermuhlner/math/big/BigRational.java deleted file mode 100644 index 2d7389c7de..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/BigRational.java +++ /dev/null @@ -1,1103 +0,0 @@ -package ch.obermuhlner.math.big; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; -import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.IntStream; - -/** - * A rational number represented as a quotient of two values. - * - *

Basic calculations with rational numbers (+ - * /) have no loss of precision. - * This allows to use {@link BigRational} as a replacement for {@link BigDecimal} if absolute accuracy is desired.

- * - *

Wikipedia: Rational number

- * - *

The values are internally stored as {@link BigDecimal} (for performance optimizations) but represented - * as {@link BigInteger} (for mathematical correctness) - * when accessed with {@link #getNumeratorBigInteger()} and {@link #getDenominatorBigInteger()}.

- * - *

The following basic calculations have no loss of precision:

- *
    - *
  • {@link #add(BigRational)}
  • - *
  • {@link #subtract(BigRational)}
  • - *
  • {@link #multiply(BigRational)}
  • - *
  • {@link #divide(BigRational)}
  • - *
  • {@link #pow(int)}
  • - *
- * - *

The following calculations are special cases of the ones listed above and have no loss of precision:

- *
    - *
  • {@link #negate()}
  • - *
  • {@link #reciprocal()}
  • - *
  • {@link #increment()}
  • - *
  • {@link #decrement()}
  • - *
- * - *

Any {@link BigRational} value can be converted into an arbitrary {@link #withPrecision(int) precision} (number of significant digits) - * or {@link #withScale(int) scale} (number of digits after the decimal point).

- */ -public class BigRational implements Comparable { - - /** - * The value 0 as {@link BigRational}. - */ - public static final BigRational ZERO = new BigRational(0); - /** - * The value 1 as {@link BigRational}. - */ - public static final BigRational ONE = new BigRational(1); - /** - * The value 2 as {@link BigRational}. - */ - public static final BigRational TWO = new BigRational(2); - /** - * The value 10 as {@link BigRational}. - */ - public static final BigRational TEN = new BigRational(10); - - private final BigDecimal numerator; - - private final BigDecimal denominator; - - private BigRational(int value) { - this(BigDecimal.valueOf(value), BigDecimal.ONE); - } - - private BigRational(BigDecimal num, BigDecimal denom) { - BigDecimal n = num; - BigDecimal d = denom; - - if (d.signum() == 0) { - throw new ArithmeticException("Divide by zero"); - } - - if (d.signum() < 0) { - n = n.negate(); - d = d.negate(); - } - - numerator = n; - denominator = d; - } - - /** - * Returns the numerator of this rational number as BigInteger. - * - * @return the numerator as BigInteger - */ - public BigInteger getNumeratorBigInteger() { - return numerator.toBigInteger(); - } - - /** - * Returns the numerator of this rational number as BigDecimal. - * - * @return the numerator as BigDecimal - */ - public BigDecimal getNumerator() { - return numerator; - } - - /** - * Returns the denominator of this rational number as BigInteger. - * - *

Guaranteed to not be 0.

- *

Guaranteed to be positive.

- * - * @return the denominator as BigInteger - */ - public BigInteger getDenominatorBigInteger() { - return denominator.toBigInteger(); - } - - /** - * Returns the denominator of this rational number as BigDecimal. - * - *

Guaranteed to not be 0.

- *

Guaranteed to be positive.

- * - * @return the denominator as BigDecimal - */ - public BigDecimal getDenominator() { - return denominator; - } - - /** - * Reduces this rational number to the smallest numerator/denominator with the same value. - * - * @return the reduced rational number - */ - public BigRational reduce() { - BigInteger n = numerator.toBigInteger(); - BigInteger d = denominator.toBigInteger(); - - BigInteger gcd = n.gcd(d); - n = n.divide(gcd); - d = d.divide(gcd); - - return valueOf(n, d); - } - - /** - * Returns the integer part of this rational number. - * - *

Examples:

- *
    - *
  • BigRational.valueOf(3.5).integerPart() returns BigRational.valueOf(3)
  • - *
- * - * @return the integer part of this rational number - */ - public BigRational integerPart() { - return of(numerator.subtract(numerator.remainder(denominator)), denominator); - } - - /** - * Returns the fraction part of this rational number. - * - *

Examples:

- *
    - *
  • BigRational.valueOf(3.5).integerPart() returns BigRational.valueOf(0.5)
  • - *
- * - * @return the fraction part of this rational number - */ - public BigRational fractionPart() { - return of(numerator.remainder(denominator), denominator); - } - - /** - * Negates this rational number (inverting the sign). - * - *

The result has no loss of precision.

- * - *

Examples:

- *
    - *
  • BigRational.valueOf(3.5).negate() returns BigRational.valueOf(-3.5)
  • - *
- * - * @return the negated rational number - */ - public BigRational negate() { - if (isZero()) { - return this; - } - - return of(numerator.negate(), denominator); - } - - /** - * Calculates the reciprocal of this rational number (1/x). - * - *

The result has no loss of precision.

- * - *

Examples:

- *
    - *
  • BigRational.valueOf(0.5).reciprocal() returns BigRational.valueOf(2)
  • - *
  • BigRational.valueOf(-2).reciprocal() returns BigRational.valueOf(-0.5)
  • - *
- * - * @return the reciprocal rational number - * @throws ArithmeticException if this number is 0 (division by zero) - */ - public BigRational reciprocal() { - return of(denominator, numerator); - } - - /** - * Returns the absolute value of this rational number. - * - *

The result has no loss of precision.

- * - *

Examples:

- *
    - *
  • BigRational.valueOf(-2).abs() returns BigRational.valueOf(2)
  • - *
  • BigRational.valueOf(2).abs() returns BigRational.valueOf(2)
  • - *
- * - * @return the absolute rational number (positive, or 0 if this rational is 0) - */ - public BigRational abs() { - return isPositive() ? this : negate(); - } - - /** - * Returns the signum function of this rational number. - * - * @return -1, 0 or 1 as the value of this rational number is negative, zero or positive. - */ - public int signum() { - return numerator.signum(); - } - - /** - * Calculates the increment of this rational number (+ 1). - * - *

This is functionally identical to - * this.add(BigRational.ONE) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @return the incremented rational number - */ - public BigRational increment() { - return of(numerator.add(denominator), denominator); - } - - /** - * Calculates the decrement of this rational number (- 1). - * - *

This is functionally identical to - * this.subtract(BigRational.ONE) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @return the decremented rational number - */ - public BigRational decrement() { - return of(numerator.subtract(denominator), denominator); - } - - /** - * Calculates the addition (+) of this rational number and the specified argument. - * - *

The result has no loss of precision.

- * - * @param value the rational number to add - * @return the resulting rational number - */ - public BigRational add(BigRational value) { - if (denominator.equals(value.denominator)) { - return of(numerator.add(value.numerator), denominator); - } - - BigDecimal n = numerator.multiply(value.denominator).add(value.numerator.multiply(denominator)); - BigDecimal d = denominator.multiply(value.denominator); - return of(n, d); - } - - private BigRational add(BigDecimal value) { - return of(numerator.add(value.multiply(denominator)), denominator); - } - - /** - * Calculates the addition (+) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.add(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the {@link BigInteger} to add - * @return the resulting rational number - */ - public BigRational add(BigInteger value) { - if (value.equals(BigInteger.ZERO)) { - return this; - } - return add(new BigDecimal(value)); - } - - /** - * Calculates the addition (+) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.add(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the int value to add - * @return the resulting rational number - */ - public BigRational add(int value) { - if (value == 0) { - return this; - } - return add(BigInteger.valueOf(value)); - } - - /** - * Calculates the subtraction (-) of this rational number and the specified argument. - * - *

The result has no loss of precision.

- * - * @param value the rational number to subtract - * @return the resulting rational number - */ - public BigRational subtract(BigRational value) { - if (denominator.equals(value.denominator)) { - return of(numerator.subtract(value.numerator), denominator); - } - - BigDecimal n = numerator.multiply(value.denominator).subtract(value.numerator.multiply(denominator)); - BigDecimal d = denominator.multiply(value.denominator); - return of(n, d); - } - - private BigRational subtract(BigDecimal value) { - return of(numerator.subtract(value.multiply(denominator)), denominator); - } - - /** - * Calculates the subtraction (-) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.subtract(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the {@link BigInteger} to subtract - * @return the resulting rational number - */ - public BigRational subtract(BigInteger value) { - if (value.equals(BigInteger.ZERO)) { - return this; - } - return subtract(new BigDecimal(value)); - } - - /** - * Calculates the subtraction (-) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.subtract(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the int value to subtract - * @return the resulting rational number - */ - public BigRational subtract(int value) { - if (value == 0) { - return this; - } - return subtract(BigInteger.valueOf(value)); - } - - /** - * Calculates the multiplication (*) of this rational number and the specified argument. - * - *

The result has no loss of precision.

- * - * @param value the rational number to multiply - * @return the resulting rational number - */ - public BigRational multiply(BigRational value) { - if (isZero() || value.isZero()) { - return ZERO; - } - if (equals(ONE)) { - return value; - } - if (value.equals(ONE)) { - return this; - } - - BigDecimal n = numerator.multiply(value.numerator); - BigDecimal d = denominator.multiply(value.denominator); - return of(n, d); - } - - // private, because we want to hide that we use BigDecimal internally - private BigRational multiply(BigDecimal value) { - BigDecimal n = numerator.multiply(value); - BigDecimal d = denominator; - return of(n, d); - } - - /** - * Calculates the multiplication (*) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.multiply(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the {@link BigInteger} to multiply - * @return the resulting rational number - */ - public BigRational multiply(BigInteger value) { - if (isZero() || value.signum() == 0) { - return ZERO; - } - if (equals(ONE)) { - return valueOf(value); - } - if (value.equals(BigInteger.ONE)) { - return this; - } - - return multiply(new BigDecimal(value)); - } - - /** - * Calculates the multiplication (*) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.multiply(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the int value to multiply - * @return the resulting rational number - */ - public BigRational multiply(int value) { - return multiply(BigInteger.valueOf(value)); - } - - /** - * Calculates the division (/) of this rational number and the specified argument. - * - *

The result has no loss of precision.

- * - * @param value the rational number to divide (0 is not allowed) - * @return the resulting rational number - * @throws ArithmeticException if the argument is 0 (division by zero) - */ - public BigRational divide(BigRational value) { - if (value.equals(ONE)) { - return this; - } - - BigDecimal n = numerator.multiply(value.denominator); - BigDecimal d = denominator.multiply(value.numerator); - return of(n, d); - } - - private BigRational divide(BigDecimal value) { - BigDecimal n = numerator; - BigDecimal d = denominator.multiply(value); - return of(n, d); - } - - /** - * Calculates the division (/) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.divide(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the {@link BigInteger} to divide (0 is not allowed) - * @return the resulting rational number - * @throws ArithmeticException if the argument is 0 (division by zero) - */ - public BigRational divide(BigInteger value) { - if (value.equals(BigInteger.ONE)) { - return this; - } - - return divide(new BigDecimal(value)); - } - - /** - * Calculates the division (/) of this rational number and the specified argument. - * - *

This is functionally identical to - * this.divide(BigRational.valueOf(value)) - * but slightly faster.

- * - *

The result has no loss of precision.

- * - * @param value the int value to divide (0 is not allowed) - * @return the resulting rational number - * @throws ArithmeticException if the argument is 0 (division by zero) - */ - public BigRational divide(int value) { - return divide(BigInteger.valueOf(value)); - } - - /** - * Returns whether this rational number is zero. - * - * @return true if this rational number is zero (0), false if it is not zero - */ - public boolean isZero() { - return numerator.signum() == 0; - } - - private boolean isPositive() { - return numerator.signum() > 0; - } - - /** - * Returns whether this rational number is an integer number without fraction part. - * - * @return true if this rational number is an integer number, false if it has a fraction part - */ - public boolean isInteger() { - return isIntegerInternal() || reduce().isIntegerInternal(); - } - - /** - * Returns whether this rational number is an integer number without fraction part. - * - *

Will return false if this number is not reduced to the integer representation yet (e.g. 4/4 or 4/2)

- * - * @return true if this rational number is an integer number, false if it has a fraction part - * @see #isInteger() - */ - private boolean isIntegerInternal() { - return denominator.compareTo(BigDecimal.ONE) == 0; - } - - /** - * Calculates this rational number to the power (xy) of the specified argument. - * - *

The result has no loss of precision.

- * - * @param exponent exponent to which this rational number is to be raised - * @return the resulting rational number - */ - public BigRational pow(int exponent) { - if (exponent == 0) { - return ONE; - } - if (exponent == 1) { - return this; - } - - final BigInteger n; - final BigInteger d; - if (exponent > 0) { - n = numerator.toBigInteger().pow(exponent); - d = denominator.toBigInteger().pow(exponent); - } - else { - n = denominator.toBigInteger().pow(-exponent); - d = numerator.toBigInteger().pow(-exponent); - } - return valueOf(n, d); - } - - /** - * Finds the minimum (smaller) of two rational numbers. - * - * @param value the rational number to compare with - * @return the minimum rational number, either this or the argument value - */ - private BigRational min(BigRational value) { - return compareTo(value) <= 0 ? this : value; - } - - /** - * Finds the maximum (larger) of two rational numbers. - * - * @param value the rational number to compare with - * @return the minimum rational number, either this or the argument value - */ - private BigRational max(BigRational value) { - return compareTo(value) >= 0 ? this : value; - } - - /** - * Returns a rational number with approximatively this value and the specified precision. - * - * @param precision the precision (number of significant digits) of the calculated result, or 0 for unlimited precision - * @return the calculated rational number with the specified precision - */ - public BigRational withPrecision(int precision) { - return valueOf(toBigDecimal(new MathContext(precision))); - } - - /** - * Returns a rational number with approximatively this value and the specified scale. - * - * @param scale the scale (number of digits after the decimal point) of the calculated result - * @return the calculated rational number with the specified scale - */ - public BigRational withScale(int scale) { - return valueOf(toBigDecimal().setScale(scale, RoundingMode.HALF_UP)); - } - - private static int countDigits(BigInteger number) { - double factor = Math.log(2) / Math.log(10); - int digitCount = (int) (factor * number.bitLength() + 1); - if (BigInteger.TEN.pow(digitCount - 1).compareTo(number) > 0) { - return digitCount - 1; - } - return digitCount; - } - - // TODO what is precision of a rational? - private int precision() { - return countDigits(numerator.toBigInteger()) + countDigits(denominator.toBigInteger()); - } - - /** - * Returns this rational number as a double value. - * - * @return the double value - */ - public double toDouble() { - // TODO best accuracy or maybe bigDecimalValue().doubleValue() is better? - return numerator.doubleValue() / denominator.doubleValue(); - } - - /** - * Returns this rational number as a float value. - * - * @return the float value - */ - public float toFloat() { - return numerator.floatValue() / denominator.floatValue(); - } - - /** - * Returns this rational number as a {@link BigDecimal}. - * - * @return the {@link BigDecimal} value - */ - public BigDecimal toBigDecimal() { - int precision = Math.max(precision(), MathContext.DECIMAL128.getPrecision()); - return toBigDecimal(new MathContext(precision)); - } - - /** - * Returns this rational number as a {@link BigDecimal} with the precision specified by the {@link MathContext}. - * - * @param mc the {@link MathContext} specifying the precision of the calculated result - * @return the {@link BigDecimal} - */ - public BigDecimal toBigDecimal(MathContext mc) { - return numerator.divide(denominator, mc); - } - - @Override - public int compareTo(BigRational other) { - if (this == other) { - return 0; - } - return numerator.multiply(other.denominator).compareTo(denominator.multiply(other.numerator)); - } - - @Override - public int hashCode() { - if (isZero()) { - return 0; - } - return numerator.hashCode() + denominator.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (!(obj instanceof BigRational)) { - return false; - } - - BigRational other = (BigRational) obj; - if (!numerator.equals(other.numerator)) { - return false; - } - return denominator.equals(other.denominator); - } - - @Override - public String toString() { - if (isZero()) { - return "0"; - } - if (isIntegerInternal()) { - return numerator.toString(); - } - return toBigDecimal().toString(); - } - - /** - * Returns a plain string representation of this rational number without any exponent. - * - * @return the plain string representation - * @see BigDecimal#toPlainString() - */ - public String toPlainString() { - if (isZero()) { - return "0"; - } - if (isIntegerInternal()) { - return numerator.toPlainString(); - } - return toBigDecimal().toPlainString(); - } - - /** - * Returns the string representation of this rational number in the form "numerator/denominator". - * - *

The resulting string is a valid input of the {@link #valueOf(String)} method.

- * - *

Examples:

- *
    - *
  • BigRational.valueOf(0.5).toRationalString() returns "1/2"
  • - *
  • BigRational.valueOf(2).toRationalString() returns "2"
  • - *
  • BigRational.valueOf(4, 4).toRationalString() returns "4/4" (not reduced)
  • - *
- * - * @return the rational number string representation in the form "numerator/denominator", or "0" if the rational number is 0. - * @see #valueOf(String) - * @see #valueOf(int, int) - */ - public String toRationalString() { - if (isZero()) { - return "0"; - } - if (isIntegerInternal()) { - return numerator.toString(); - } - return numerator + "/" + denominator; - } - - /** - * Returns the string representation of this rational number as integer and fraction parts in the form "integerPart fractionNominator/fractionDenominator". - * - *

The integer part is omitted if it is 0 (when this absolute rational number is smaller than 1).

- *

The fraction part is omitted it it is 0 (when this rational number is an integer).

- *

If this rational number is 0, then "0" is returned.

- * - *

Example: BigRational.valueOf(3.5).toIntegerRationalString() returns "3 1/2".

- * - * @return the integer and fraction rational string representation - * @see #valueOf(int, int, int) - */ - public String toIntegerRationalString() { - BigDecimal fractionNumerator = numerator.remainder(denominator); - BigDecimal integerNumerator = numerator.subtract(fractionNumerator); - BigDecimal integerPart = integerNumerator.divide(denominator); - - StringBuilder result = new StringBuilder(); - if (integerPart.signum() != 0) { - result.append(integerPart); - } - if (fractionNumerator.signum() != 0) { - if (result.length() > 0) { - result.append(' '); - } - result.append(fractionNumerator.abs()); - result.append('/'); - result.append(denominator); - } - if (result.length() == 0) { - result.append('0'); - } - - return result.toString(); - } - - /** - * Creates a rational number of the specified int value. - * - * @param value the int value - * @return the rational number - */ - public static BigRational valueOf(int value) { - if (value == 0) { - return ZERO; - } - if (value == 1) { - return ONE; - } - return new BigRational(value); - } - - /** - * Creates a rational number of the specified numerator/denominator int values. - * - * @param numerator the numerator int value - * @param denominator the denominator int value (0 not allowed) - * @return the rational number - * @throws ArithmeticException if the denominator is 0 (division by zero) - */ - public static BigRational valueOf(int numerator, int denominator) { - return of(BigDecimal.valueOf(numerator), BigDecimal.valueOf(denominator)); - } - - /** - * Creates a rational number of the specified integer and fraction parts. - * - *

Useful to create numbers like 3 1/2 (= three and a half = 3.5) by calling - * BigRational.valueOf(3, 1, 2).

- *

To create a negative rational only the integer part argument is allowed to be negative: - * to create -3 1/2 (= minus three and a half = -3.5) call BigRational.valueOf(-3, 1, 2).

- * - * @param integer the integer part int value - * @param fractionNumerator the fraction part numerator int value (negative not allowed) - * @param fractionDenominator the fraction part denominator int value (0 or negative not allowed) - * @return the rational number - * @throws ArithmeticException if the fraction part denominator is 0 (division by zero), - * or if the fraction part numerator or denominator is negative - */ - public static BigRational valueOf(int integer, int fractionNumerator, int fractionDenominator) { - if (fractionNumerator < 0 || fractionDenominator < 0) { - throw new ArithmeticException("Negative value"); - } - - BigRational integerPart = valueOf(integer); - BigRational fractionPart = valueOf(fractionNumerator, fractionDenominator); - return integerPart.isPositive() ? integerPart.add(fractionPart) : integerPart.subtract(fractionPart); - } - - /** - * Creates a rational number of the specified numerator/denominator BigInteger values. - * - * @param numerator the numerator {@link BigInteger} value - * @param denominator the denominator {@link BigInteger} value (0 not allowed) - * @return the rational number - * @throws ArithmeticException if the denominator is 0 (division by zero) - */ - public static BigRational valueOf(BigInteger numerator, BigInteger denominator) { - return of(new BigDecimal(numerator), new BigDecimal(denominator)); - } - - /** - * Creates a rational number of the specified {@link BigInteger} value. - * - * @param value the {@link BigInteger} value - * @return the rational number - */ - public static BigRational valueOf(BigInteger value) { - if (value.compareTo(BigInteger.ZERO) == 0) { - return ZERO; - } - if (value.compareTo(BigInteger.ONE) == 0) { - return ONE; - } - return valueOf(value, BigInteger.ONE); - } - - /** - * Creates a rational number of the specified double value. - * - * @param value the double value - * @return the rational number - * @throws NumberFormatException if the double value is Infinite or NaN. - */ - public static BigRational valueOf(double value) { - if (value == 0.0) { - return ZERO; - } - if (value == 1.0) { - return ONE; - } - if (Double.isInfinite(value)) { - throw new NumberFormatException("Infinite"); - } - if (Double.isNaN(value)) { - throw new NumberFormatException("NaN"); - } - return valueOf(new BigDecimal(String.valueOf(value))); - } - - /** - * Creates a rational number of the specified {@link BigDecimal} value. - * - * @param value the double value - * @return the rational number - */ - public static BigRational valueOf(BigDecimal value) { - if (value.compareTo(BigDecimal.ZERO) == 0) { - return ZERO; - } - if (value.compareTo(BigDecimal.ONE) == 0) { - return ONE; - } - - int scale = value.scale(); - if (scale == 0) { - return new BigRational(value, BigDecimal.ONE); - } else if (scale < 0) { - BigDecimal n = new BigDecimal(value.unscaledValue()).multiply(BigDecimal.ONE.movePointLeft(value.scale())); - return new BigRational(n, BigDecimal.ONE); - } - else { - BigDecimal n = new BigDecimal(value.unscaledValue()); - BigDecimal d = BigDecimal.ONE.movePointRight(value.scale()); - return new BigRational(n, d); - } - } - - /** - * Creates a rational number of the specified string representation. - * - *

The accepted string representations are:

- *
    - *
  • Output of {@link BigRational#toString()} : "integerPart.fractionPart"
  • - *
  • Output of {@link BigRational#toRationalString()} : "numerator/denominator"
  • - *
  • Output of toString() of {@link BigDecimal}, {@link BigInteger}, {@link Integer}, ...
  • - *
  • Output of toString() of {@link Double}, {@link Float} - except "Infinity", "-Infinity" and "NaN"
  • - *
- * - * @param string the string representation to convert - * @return the rational number - * @throws ArithmeticException if the denominator is 0 (division by zero) - */ - public static BigRational valueOf(String string) { - String[] strings = string.split("/"); - BigRational result = valueOfSimple(strings[0]); - for (int i = 1; i < strings.length; i++) { - result = result.divide(valueOfSimple(strings[i])); - } - return result; - } - - private static BigRational valueOfSimple(String string) { - return valueOf(new BigDecimal(string)); - } - - public static BigRational valueOf(boolean positive, String integerPart, String fractionPart, String fractionRepeatPart, String exponentPart) { - BigRational result = ZERO; - - if (fractionRepeatPart != null && fractionRepeatPart.length() > 0) { - BigInteger lotsOfNines = BigInteger.TEN.pow(fractionRepeatPart.length()).subtract(BigInteger.ONE); - result = valueOf(new BigInteger(fractionRepeatPart), lotsOfNines); - } - - if (fractionPart != null && fractionPart.length() > 0) { - result = result.add(valueOf(new BigInteger(fractionPart))); - result = result.divide(BigInteger.TEN.pow(fractionPart.length())); - } - - if (integerPart != null && integerPart.length() > 0) { - result = result.add(new BigInteger(integerPart)); - } - - if (exponentPart != null && exponentPart.length() > 0) { - int exponent = Integer.parseInt(exponentPart); - BigInteger powerOfTen = BigInteger.TEN.pow(Math.abs(exponent)); - result = exponent >= 0 ? result.multiply(powerOfTen) : result.divide(powerOfTen); - } - - if (!positive) { - result = result.negate(); - } - - return result; - } - - /** - * Creates a rational number of the specified numerator/denominator BigDecimal values. - * - * @param numerator the numerator {@link BigDecimal} value - * @param denominator the denominator {@link BigDecimal} value (0 not allowed) - * @return the rational number - * @throws ArithmeticException if the denominator is 0 (division by zero) - */ - public static BigRational valueOf(BigDecimal numerator, BigDecimal denominator) { - return valueOf(numerator).divide(valueOf(denominator)); - } - - private static BigRational of(BigDecimal numerator, BigDecimal denominator) { - if (numerator.signum() == 0 && denominator.signum() != 0) { - return ZERO; - } - if (numerator.compareTo(BigDecimal.ONE) == 0 && denominator.compareTo(BigDecimal.ONE) == 0) { - return ONE; - } - return new BigRational(numerator, denominator); - } - - /** - * Returns the smallest of the specified rational numbers. - * - * @param values the rational numbers to compare - * @return the smallest rational number, 0 if no numbers are specified - */ - public static BigRational min(BigRational... values) { - if (values.length == 0) { - return BigRational.ZERO; - } - BigRational result = values[0]; - for (int i = 1; i < values.length; i++) { - result = result.min(values[i]); - } - return result; - } - - /** - * Returns the largest of the specified rational numbers. - * - * @param values the rational numbers to compare - * @return the largest rational number, 0 if no numbers are specified - * @see #max(BigRational) - */ - public static BigRational max(BigRational... values) { - if (values.length == 0) { - return BigRational.ZERO; - } - BigRational result = values[0]; - for (int i = 1; i < values.length; i++) { - result = result.max(values[i]); - } - return result; - } - - private static List bernoulliCache = new ArrayList<>(); - - /** - * Calculates the Bernoulli number for the specified index. - * - *

This function calculates the first Bernoulli numbers and therefore bernoulli(1) returns -0.5

- *

Note that bernoulli(x) for all odd x > 1 returns 0

- *

See: Wikipedia: Bernoulli number

- * - * @param n the index of the Bernoulli number to be calculated (starting at 0) - * @return the Bernoulli number for the specified index - * @throws ArithmeticException if x is lesser than 0 - */ - public static BigRational bernoulli(int n) { - if (n < 0) { - throw new ArithmeticException("Illegal bernoulli(n) for n < 0: n = " + n); - } - if (n == 1) { - return valueOf(-1, 2); - } else if (n % 2 == 1) { - return ZERO; - } - - synchronized (bernoulliCache) { - int index = n / 2; - - if (bernoulliCache.size() <= index) { - for (int i = bernoulliCache.size(); i <= index; i++) { - BigRational b = calculateBernoulli(i * 2); - bernoulliCache.add(b); - } - } - - return bernoulliCache.get(index); - } - } - - private static BigRational calculateBernoulli(int n) { - return IntStream.rangeClosed(0, n).parallel().mapToObj(k -> { - BigRational jSum = ZERO ; - BigRational bin = ONE ; - for(int j=0 ; j <= k ; j++) { - BigRational jPowN = valueOf(j).pow(n); - if (j % 2 == 0) { - jSum = jSum.add(bin.multiply(jPowN)) ; - } else { - jSum = jSum.subtract(bin.multiply(jPowN)) ; - } - - bin = bin.multiply(valueOf(k-j).divide(valueOf(j+1))); - } - return jSum.divide(valueOf(k+1)); - }).reduce(ZERO, BigRational::add); - } - -} diff --git a/src/main/java/ch/obermuhlner/math/big/DefaultBigDecimalMath.java b/src/main/java/ch/obermuhlner/math/big/DefaultBigDecimalMath.java deleted file mode 100644 index d6dca31ecf..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/DefaultBigDecimalMath.java +++ /dev/null @@ -1,736 +0,0 @@ -package ch.obermuhlner.math.big; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.math.RoundingMode; -import java.util.*; - -/** - * A wrapper around {@link BigDecimalMath} that passes a current {@link MathContext} to the - * functions that need a {@link MathContext} argument. - * - *

The initial default {@link MathContext} is equivalent to {@link MathContext#DECIMAL128} - * but this can be overridden by setting the following system properties:

- *
    - *
  • ch.obermuhlner.math.big.default.precision to a positive integer precision (default=34)
  • - *
  • ch.obermuhlner.math.big.default.rounding to a {@link RoundingMode} name (default=HALF_UP)
  • - *
- * - *

It is also possible to programmatically set the default {@link MathContext} using {@link #setDefaultMathContext(MathContext)}. - * It is recommended to set the desired precision in the {@link 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 {@link #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 {@link MathContext} you have to choice to use either: - *

    - *
  • DefaultBigDecimalMath.createLocalMathContext() in a try-with-resources statement
  • - *
  • DefaultBigDecimalMath.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.withPrecision(5, () -> {
-    System.out.println("Pi[5]: " + DefaultBigDecimalMath.pi());
-    DefaultBigDecimalMath.withPrecision(10, () -> {
-        System.out.println("Pi[10]: " + DefaultBigDecimalMath.pi());
-    });
-    System.out.println("Pi[5]: " + DefaultBigDecimalMath.pi());
-});
-System.out.println("Pi[default]: " + DefaultBigDecimalMath.pi());
-
- * - * Both snippets with give the following ouput: - *
-Pi[default]: 3.141592653589793238462643383279503
-Pi[5]: 3.1416
-Pi[10]: 3.141592654
-Pi[5]: 3.1416
-Pi[default]: 3.141592653589793238462643383279503
-
- *

The temporary {@link MathContext} are stored in {@link ThreadLocal} variables - * and will therefore not conflict with each other when used in multi-threaded use case.

- * - *

Important: Due to the {@link ThreadLocal} variables the local {@link MathContext} will - * not be available in other threads. - * This includes streams using parallel(), thread pools and manually started threads. - * If you need temporary {@link MathContext} for calculations then you must - * set the local {@link 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);
-}
-
- */ -public class DefaultBigDecimalMath { - - private static MathContext defaultMathContext = createDefaultMathContext(); - private static ThreadLocal> mathContextStack = new ThreadLocal<>(); - - private static MathContext createDefaultMathContext () { - int precision = getIntSystemProperty("ch.obermuhlner.math.big.default.precision", MathContext.DECIMAL128.getPrecision()); - RoundingMode rounding = getRoundingModeSystemProperty("ch.obermuhlner.math.big.default.rounding", MathContext.DECIMAL128.getRoundingMode()); - - return new MathContext(precision, rounding); - } - - private static void pushMathContext(MathContext mathContext) { - Deque mathContexts = mathContextStack.get(); - if (mathContexts == null) { - mathContexts = new ArrayDeque<>(); - mathContextStack.set(mathContexts); - }; - mathContexts.addLast(mathContext); - } - - private static MathContext popMathContext() { - Deque mathContexts = mathContextStack.get(); - MathContext poppedMathContext = mathContexts.removeLast(); - if (mathContexts.isEmpty()) { - mathContextStack.remove(); - } - return poppedMathContext; - } - - private static int getIntSystemProperty(String propertyKey, int defaultValue) { - String propertyValue = System.getProperty(propertyKey, Integer.toString(defaultValue)); - try { - return Integer.parseInt(propertyValue); - } catch(NumberFormatException ex) { - return propertyException(propertyKey,propertyValue,defaultValue); - } - } - - private static RoundingMode getRoundingModeSystemProperty(String propertyKey, RoundingMode defaultValue) { - String propertyValue = System.getProperty(propertyKey, defaultValue.name()); - try { - return RoundingMode.valueOf(propertyValue); - } catch(IllegalArgumentException ex) { - return propertyException(propertyKey,propertyValue,defaultValue); - } - } - - private static T propertyException(String propertyKey,String propertyValue,T defaultValue){ - System.err.println("Property '" + propertyKey + "' is not valid: " + propertyValue + " (using " + defaultValue + " instead)"); - return defaultValue; - } - - /** - * Sets the default {@link MathContext} used if no other {@link MathContext} is defined using {@link #withLocalMathContext(MathContext, Runnable)}. - * - * @param defaultMathContext the default {@link MathContext} - * @see #currentMathContext() - * @see #withLocalMathContext(int, Runnable) - * @see #withLocalMathContext(int, RoundingMode, Runnable) - * @see #withLocalMathContext(MathContext, Runnable) - */ - public static void setDefaultMathContext(MathContext defaultMathContext) { - Objects.requireNonNull(defaultMathContext); - DefaultBigDecimalMath.defaultMathContext = defaultMathContext; - } - - /** - * Returns the default {@link MathContext} used for all mathematical functions in this class. - * - * @return the default {@link MathContext} - */ - public static MathContext getDefaultMathContext() { - return defaultMathContext; - } - - /** - * Executes the given {@link Runnable} using the specified precision. - * - * @param precision the precision to use for calculations in the runnable - * @param runnable the {@link Runnable} to execute - */ - public static void withLocalMathContext(int precision, Runnable runnable) { - withLocalMathContext(new MathContext(precision), runnable); - } - - /** - * Executes the given {@link Runnable} using the specified precision and {@link RoundingMode}. - * - * @param precision the precision to use for calculations in the runnable - * @param roundingMode the {@link RoundingMode} to use for calculations in the runnable - * @param runnable the {@link Runnable} to execute - */ - public static void withLocalMathContext(int precision, RoundingMode roundingMode, Runnable runnable) { - withLocalMathContext(new MathContext(precision, roundingMode), runnable); - } - - /** - * Executes the given {@link Runnable} using the specified {@link MathContext}. - * - * @param mathContext the {@link MathContext} to use for calculations in the runnable - * @param runnable the {@link Runnable} to execute - */ - public static void withLocalMathContext(MathContext mathContext, Runnable runnable) { - try (LocalMathContext context = createLocalMathContext(mathContext)) { - runnable.run(); - } - } - - /** - * Executes the given {@link Runnable} using the specified precision. - * - * @param precision the precision to use for calculations - * @return the created {@link LocalMathContext} to be used in a try-with-resources statement - */ - public static LocalMathContext createLocalMathContext(int precision) { - return createLocalMathContext(new MathContext(precision)); - } - - /** - * Executes the given {@link Runnable} using the specified precision and {@link RoundingMode}. - * - * @param precision the precision to use for calculations - * @param roundingMode the {@link RoundingMode} to use for calculations in the runnable - * @return the created {@link LocalMathContext} to be used in a try-with-resources statement - */ - public static LocalMathContext createLocalMathContext(int precision, RoundingMode roundingMode) { - return createLocalMathContext(new MathContext(precision, roundingMode)); - } - - /** - * Executes the given {@link Runnable} using the specified {@link MathContext}. - * - * @param mathContext the {@link MathContext} to use for calculations - * @return the created {@link LocalMathContext} to be used in a try-with-resources statement - */ - public static LocalMathContext createLocalMathContext(MathContext mathContext) { - return new LocalMathContext(mathContext); - } - - /** - * Returns the current {@link MathContext} used for all mathematical functions in this class. - * - *

The current {@link MathContext} is the last {@link MathContext} specified - * using {@link #withLocalMathContext(MathContext, Runnable)} - * or the default {@link MathContext} if none was specified.

- * - * @return the current {@link MathContext} - * @see #currentMathContext() - * @see #withLocalMathContext(int, Runnable) - * @see #withLocalMathContext(int, RoundingMode, Runnable) - * @see #withLocalMathContext(MathContext, Runnable) - */ - public static MathContext currentMathContext() { - Deque mathContexts = mathContextStack.get(); - if (mathContexts == null || mathContexts.isEmpty()) { - return defaultMathContext; - } - - return mathContexts.getLast(); - } - - /** - * Rounds the specified {@link BigDecimal} to the precision of the current {@link MathContext}. - * - * @param value the {@link BigDecimal} to round - * @return the rounded {@link BigDecimal} value - * @see #currentMathContext() - * @see BigDecimalMath#round(BigDecimal, MathContext) - */ - public static BigDecimal round(BigDecimal value) { - return BigDecimalMath.round(value, defaultMathContext); - } - - /** - * Rounds the specified {@link BigDecimal} to the precision of the current {@link MathContext} including trailing zeroes. - * - * @param value the {@link BigDecimal} to round - * @return the rounded {@link BigDecimal} value including trailing zeroes - * @see #currentMathContext() - * @see BigDecimalMath#roundWithTrailingZeroes(BigDecimal, MathContext) - */ - public static BigDecimal roundWithTrailingZeroes(BigDecimal value) { - return BigDecimalMath.roundWithTrailingZeroes(value, currentMathContext()); - } - - /** - * Returns the {@link BigDecimal} that is x + y using the current {@link MathContext}. - * - * @param x the x value - * @param y the y value to add - * @return the resulting {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimal#add(BigDecimal, MathContext) - */ - public static BigDecimal add(BigDecimal x, BigDecimal y) { - return x.add(y, currentMathContext()); - } - - /** - * Returns the {@link BigDecimal} that is x - y using the current {@link MathContext}. - * - * @param x the x value - * @param y the y value to subtract - * @return the resulting {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimal#subtract(BigDecimal, MathContext) - */ - public static BigDecimal subtract(BigDecimal x, BigDecimal y) { - return x.subtract(y, currentMathContext()); - } - - /** - * Returns the {@link BigDecimal} that is x * y using the current {@link MathContext}. - * - * @param x the x value - * @param y the y value to multiply - * @return the resulting {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimal#multiply(BigDecimal, MathContext) - */ - public static BigDecimal multiply(BigDecimal x, BigDecimal y) { - return x.multiply(y, currentMathContext()); - } - - /** - * Returns the {@link BigDecimal} that is x / y using the current {@link MathContext}. - * - * @param x the x value - * @param y the y value to divide - * @return the resulting {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimal#divide(BigDecimal, MathContext) - */ - public static BigDecimal divide(BigDecimal x, BigDecimal y) { - return x.divide(y, currentMathContext()); - } - - /** - * Returns the {@link BigDecimal} that is x % y using the current {@link MathContext}. - * - * @param x the x value - * @param y the y value to divide - * @return the resulting {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimal#remainder(BigDecimal, MathContext) - */ - public static BigDecimal remainder(BigDecimal x, BigDecimal y) { - return x.remainder(y, currentMathContext()); - } - - /** - * Calculates the reciprocal of the specified {@link BigDecimal} using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} - * @return the reciprocal {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#reciprocal(BigDecimal, MathContext) - */ - public static BigDecimal reciprocal(BigDecimal x) { - return BigDecimalMath.reciprocal(x, currentMathContext()); - } - - /** - * Calculates the factorial of the specified {@link BigDecimal} using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} - * @return the factorial {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#factorial(BigDecimal, MathContext) - */ - public static BigDecimal factorial(BigDecimal x) { - return BigDecimalMath.factorial(x, currentMathContext()); - } - - /** - * Calculates the gamma function of the specified {@link BigDecimal} using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} - * @return the gamma {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#gamma(BigDecimal, MathContext) - */ - public static BigDecimal gamma(BigDecimal x) { - return BigDecimalMath.gamma(x, currentMathContext()); - } - - /** - * Calculates the Bernoulli number for the specified index using the current {@link MathContext}. - * - * @param n the index of the Bernoulli number to be calculated (starting at 0) - * @return the Bernoulli number for the specified index with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#bernoulli(int, MathContext) - */ - public static BigDecimal bernoulli(int n) { - return BigDecimalMath.bernoulli(n, currentMathContext()); - } - - /** - * Calculates {@link BigDecimal} x to the power of {@link BigDecimal} y (xy) using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} value to take to the power - * @param y the {@link BigDecimal} value to serve as exponent - * @return the calculated x to the power of y with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#pow(BigDecimal, BigDecimal, MathContext) - */ - public static BigDecimal pow(BigDecimal x, BigDecimal y) { - return BigDecimalMath.pow(x, y, currentMathContext()); - } - - /** - * Calculates {@link BigDecimal} x to the power of long y (xy) using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} value to take to the power - * @param y the long value to serve as exponent - * @return the calculated x to the power of y with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#pow(BigDecimal, long, MathContext) - */ - public static BigDecimal pow(BigDecimal x, long y) { - return BigDecimalMath.pow(x, y, currentMathContext()); - } - - /** - * Calculates the square root of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} value to calculate the square root - * @return the calculated square root of x with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#sqrt(BigDecimal, MathContext) - */ - public static BigDecimal sqrt(BigDecimal x) { - return BigDecimalMath.sqrt(x, currentMathContext()); - } - - /** - * Calculates the n'th root of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} value to calculate the n'th root - * @param n the {@link BigDecimal} defining the root - * - * @return the calculated n'th root of x with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#root(BigDecimal, BigDecimal, MathContext) - */ - public static BigDecimal root(BigDecimal x, BigDecimal n) { - return BigDecimalMath.root(x, n, currentMathContext()); - } - - /** - * Calculates the natural logarithm of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the natural logarithm for - * @return the calculated natural logarithm {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#log(BigDecimal, MathContext) - */ - public static BigDecimal log(BigDecimal x) { - return BigDecimalMath.log(x, currentMathContext()); - } - - /** - * Calculates the logarithm of {@link BigDecimal} x to the base 2 using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the logarithm base 2 for - * @return the calculated natural logarithm {@link BigDecimal} to the base 2 with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#log2(BigDecimal, MathContext) - */ - public static BigDecimal log2(BigDecimal x) { - return BigDecimalMath.log2(x, currentMathContext()); - } - - /** - * Calculates the logarithm of {@link BigDecimal} x to the base 10 using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the logarithm base 10 for - * @return the calculated natural logarithm {@link BigDecimal} to the base 10 with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#log10(BigDecimal, MathContext) - */ - public static BigDecimal log10(BigDecimal x) { - return BigDecimalMath.log10(x, currentMathContext()); - } - - /** - * Returns the number pi using the current {@link MathContext}. - * - * @return the number pi with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#pi(MathContext) - */ - public static BigDecimal pi() { - return BigDecimalMath.pi(currentMathContext()); - } - - /** - * Returns the number e using the current {@link MathContext}. - * - * @return the number e with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#e(MathContext) - */ - public static BigDecimal e() { - return BigDecimalMath.e(currentMathContext()); - } - - /** - * Calculates the natural exponent of {@link BigDecimal} x (ex) using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the exponent for - * @return the calculated exponent {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#exp(BigDecimal, MathContext) - */ - public static BigDecimal exp(BigDecimal x) { - return BigDecimalMath.exp(x, currentMathContext()); - } - - /** - * Calculates the sine (sinus) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the sine for - * @return the calculated sine {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#sin(BigDecimal, MathContext) - */ - public static BigDecimal sin(BigDecimal x) { - return BigDecimalMath.sin(x, currentMathContext()); - } - - /** - * Calculates the arc sine (inverted sine) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc sine for - * @return the calculated arc sine {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#asin(BigDecimal, MathContext) - */ - public static BigDecimal asin(BigDecimal x) { - return BigDecimalMath.asin(x, currentMathContext()); - } - - /** - * Calculates the cosine (cosinus) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the cosine for - * @return the calculated cosine {@link BigDecimal} with the precision specified in the current {@link MathContext} - */ - public static BigDecimal cos(BigDecimal x) { - return BigDecimalMath.cos(x, currentMathContext()); - } - - /** - * Calculates the arc cosine (inverted cosine) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc cosine for - * @return the calculated arc sine {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#acos(BigDecimal, MathContext) - */ - public static BigDecimal acos(BigDecimal x) { - return BigDecimalMath.acos(x, currentMathContext()); - } - - /** - * Calculates the tangens of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the tangens for - * @return the calculated tangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#tan(BigDecimal, MathContext) - */ - public static BigDecimal tan(BigDecimal x) { - return BigDecimalMath.tan(x, currentMathContext()); - } - - /** - * Calculates the arc tangens (inverted tangens) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc tangens for - * @return the calculated arc tangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#atan(BigDecimal, MathContext) - */ - public static BigDecimal atan(BigDecimal x) { - return BigDecimalMath.atan(x, currentMathContext()); - } - - /** - * Calculates the arc tangens (inverted tangens) of {@link BigDecimal} y / x in the range -pi to pi using the current {@link MathContext}. - * - * @param y the {@link BigDecimal} - * @param x the {@link BigDecimal} - * @return the calculated arc tangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see #atan2(BigDecimal, BigDecimal) - */ - public static BigDecimal atan2(BigDecimal y, BigDecimal x) { - return BigDecimalMath.atan2(y, x, currentMathContext()); - } - - /** - * Calculates the cotangens of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the cotangens for - * @return the calculated cotanges {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#cot(BigDecimal, MathContext) - */ - public static BigDecimal cot(BigDecimal x) { - return BigDecimalMath.cot(x, currentMathContext()); - } - - /** - * Calculates the inverse cotangens (arc cotangens) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc cotangens for - * @return the calculated arc cotangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#acot(BigDecimal, MathContext) - */ - public static BigDecimal acot(BigDecimal x) { - return BigDecimalMath.acot(x, currentMathContext()); - } - - /** - * Calculates the hyperbolic sine of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the hyperbolic sine for - * @return the calculated hyperbolic sine {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#sinh(BigDecimal, MathContext) - */ - public static BigDecimal sinh(BigDecimal x) { - return BigDecimalMath.sinh(x, currentMathContext()); - } - - /** - * Calculates the hyperbolic cosine of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the hyperbolic cosine for - * @return the calculated hyperbolic cosine {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#cosh(BigDecimal, MathContext) - */ - public static BigDecimal cosh(BigDecimal x) { - return BigDecimalMath.cosh(x, currentMathContext()); - } - - /** - * Calculates the hyperbolic tangens of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the hyperbolic tangens for - * @return the calculated hyperbolic tangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#tanh(BigDecimal, MathContext) - */ - public static BigDecimal tanh(BigDecimal x) { - return BigDecimalMath.tanh(x, currentMathContext()); - } - - /** - * Calculates the hyperbolic cotangens of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the hyperbolic cotangens for - * @return the calculated hyperbolic cotangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#coth(BigDecimal, MathContext) - */ - public static BigDecimal coth(BigDecimal x) { - return BigDecimalMath.coth(x, currentMathContext()); - } - - /** - * Calculates the arc hyperbolic sine (inverse hyperbolic sine) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic sine for - * @return the calculated arc hyperbolic sine {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#asinh(BigDecimal, MathContext) - */ - public static BigDecimal asinh(BigDecimal x) { - return BigDecimalMath.asinh(x, currentMathContext()); - } - - /** - * Calculates the arc hyperbolic cosine (inverse hyperbolic cosine) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic cosine for - * @return the calculated arc hyperbolic cosine {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#acosh(BigDecimal, MathContext) - */ - public static BigDecimal acosh(BigDecimal x) { - return BigDecimalMath.acosh(x, currentMathContext()); - } - - /** - * Calculates the arc hyperbolic tangens (inverse hyperbolic tangens) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic tangens for - * @return the calculated arc hyperbolic tangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#atanh(BigDecimal, MathContext) - */ - public static BigDecimal atanh(BigDecimal x) { - return BigDecimalMath.atanh(x, currentMathContext()); - } - - /** - * Calculates the arc hyperbolic cotangens (inverse hyperbolic cotangens) of {@link BigDecimal} x using the current {@link MathContext}. - * - * @param x the {@link BigDecimal} to calculate the arc hyperbolic cotangens for - * @return the calculated arc hyperbolic cotangens {@link BigDecimal} with the precision specified in the current {@link MathContext} - * @see #currentMathContext() - * @see BigDecimalMath#acoth(BigDecimal, MathContext) - */ - public static BigDecimal acoth(BigDecimal x) { - return BigDecimalMath.acoth(x, currentMathContext()); - } - - /** - * The local context used to push and pop a {@link MathContext} on the stack. - * - *

The recommended way to use this class is to use the try-with-resources.

- */ - public static class LocalMathContext implements AutoCloseable { - public final MathContext mathContext; - - LocalMathContext(MathContext mathContext) { - this.mathContext = mathContext; - pushMathContext(mathContext); - } - - @Override - public void close() { - popMathContext(); - } - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/AsinCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/AsinCalculator.java deleted file mode 100644 index f8bcd4837b..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/AsinCalculator.java +++ /dev/null @@ -1,46 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -import ch.obermuhlner.math.big.BigRational; - -/** - * Calculates arc sinus using the Maclaurin series. - * - *

See Wikipedia: Taylorreihe

- * - *

No argument checking or optimizations are done. - * This implementation is not intended to be called directly.

- */ -public class AsinCalculator extends SeriesCalculator { - - public static final AsinCalculator INSTANCE = new AsinCalculator(); - - private int n = 0; - private BigRational factorial2n = BigRational.ONE; - private BigRational factorialN = BigRational.ONE; - private BigRational fourPowerN = BigRational.ONE; - - private AsinCalculator() { - } - - @Override - protected BigRational getCurrentFactor() { - BigRational factor = factorial2n.divide(fourPowerN.multiply(factorialN).multiply(factorialN).multiply(2 * n + 1)); - return factor; - } - - @Override - protected void calculateNextFactor() { - n++; - factorial2n = factorial2n.multiply(2 * n - 1).multiply(2 * n); - factorialN = factorialN.multiply(n); - fourPowerN = fourPowerN.multiply(4); - } - - @Override - protected PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext) { - return new PowerTwoNPlusOneIterator(x, mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/AtanhCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/AtanhCalculator.java deleted file mode 100644 index a2f844a094..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/AtanhCalculator.java +++ /dev/null @@ -1,40 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import ch.obermuhlner.math.big.BigRational; - -import java.math.BigDecimal; -import java.math.MathContext; - -/** - * Calculates sinus hyperbolicus using the Taylor series. - * - *

See Wikipedia: Taylor series

- * - *

No argument checking or optimizations are done. - * This implementation is not intended to be called directly.

- */ -public class AtanhCalculator extends SeriesCalculator { - - public static final AtanhCalculator INSTANCE = new AtanhCalculator(); - - private int n = 0; - - private AtanhCalculator() { - super(true); - } - - @Override - protected BigRational getCurrentFactor() { - return BigRational.valueOf(1, 2 * n + 1); - } - - @Override - protected void calculateNextFactor() { - n++; - } - - @Override - protected PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext) { - return new PowerTwoNPlusOneIterator(x, mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/CosCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/CosCalculator.java deleted file mode 100644 index bf9edbd691..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/CosCalculator.java +++ /dev/null @@ -1,48 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -import ch.obermuhlner.math.big.BigRational; - -/** - * Calculates cosinus using the Maclaurin series. - * - *

See Wikipedia: Taylorreihe

- * - *

No argument checking or optimizations are done. - * This implementation is not intended to be called directly.

- */ -public class CosCalculator extends SeriesCalculator { - - public static final CosCalculator INSTANCE = new CosCalculator(); - - private int n = 0; - private boolean negative = false; - private BigRational factorial2n = BigRational.ONE; - - private CosCalculator() { - super(true); - } - - @Override - protected BigRational getCurrentFactor() { - BigRational factor = factorial2n.reciprocal(); - if (negative) { - factor = factor.negate(); - } - return factor; - } - - @Override - protected void calculateNextFactor() { - n++; - factorial2n = factorial2n.multiply(2 * n - 1).multiply(2 * n); - negative = !negative; - } - - @Override - protected PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext) { - return new PowerTwoNIterator(x, mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/CoshCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/CoshCalculator.java deleted file mode 100644 index f22631e8ae..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/CoshCalculator.java +++ /dev/null @@ -1,43 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -import ch.obermuhlner.math.big.BigRational; - -/** - * Calculates cosinus hyperbolicus using the Taylor series. - * - *

See Wikipedia: Taylor series

- * - *

No argument checking or optimizations are done. - * This implementation is not intended to be called directly.

- */ -public class CoshCalculator extends SeriesCalculator { - - public static final CoshCalculator INSTANCE = new CoshCalculator(); - - private int n = 0; - - private BigRational factorial2n = BigRational.ONE; - - private CoshCalculator() { - super(true); - } - - @Override - protected BigRational getCurrentFactor() { - return factorial2n.reciprocal(); - } - - @Override - protected void calculateNextFactor() { - n++; - factorial2n = factorial2n.multiply(2 * n - 1).multiply(2 * n); - } - - @Override - protected PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext) { - return new PowerTwoNIterator(x, mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/ExpCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/ExpCalculator.java deleted file mode 100644 index 16c6e6ac21..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/ExpCalculator.java +++ /dev/null @@ -1,42 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -import ch.obermuhlner.math.big.BigRational; - -/** - * Calculates exp using the Maclaurin series. - * - *

See Wikipedia: Taylorreihe

- * - *

No argument checking or optimizations are done. - * This implementation is not intended to be called directly.

- */ -public class ExpCalculator extends SeriesCalculator { - - public static final ExpCalculator INSTANCE = new ExpCalculator(); - - private int n = 0; - private BigRational oneOverFactorialOfN = BigRational.ONE; - - private ExpCalculator() { - // prevent instances - } - - @Override - protected BigRational getCurrentFactor() { - return oneOverFactorialOfN; - } - - @Override - protected void calculateNextFactor() { - n++; - oneOverFactorialOfN = oneOverFactorialOfN.divide(n); - } - - @Override - protected PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext) { - return new PowerNIterator(x, mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/PowerIterator.java b/src/main/java/ch/obermuhlner/math/big/internal/PowerIterator.java deleted file mode 100644 index def0f5f7ef..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/PowerIterator.java +++ /dev/null @@ -1,28 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; - -/** - * Iterator over the powers of a value x. - * - *

This API allows to efficiently calculate the various powers of x in a taylor series by storing intermediate results.

- *

For example xn can be calculated using one multiplication by storing the previously calculated xn-1 and x.

- * - *

{@link #getCurrentPower()} will be called first to retrieve the initial value.

- * - * For later iterations {@link #calculateNextPower()} will be called before {@link #getCurrentPower()}. - */ -public interface PowerIterator { - - /** - * Returns the current power. - * - * @return the current power. - */ - BigDecimal getCurrentPower(); - - /** - * Calculates the next power. - */ - void calculateNextPower(); -} \ No newline at end of file diff --git a/src/main/java/ch/obermuhlner/math/big/internal/PowerNIterator.java b/src/main/java/ch/obermuhlner/math/big/internal/PowerNIterator.java deleted file mode 100644 index d6ef34e01e..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/PowerNIterator.java +++ /dev/null @@ -1,33 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -/** - * {@link PowerIterator} to calculate xn. - */ -public class PowerNIterator implements PowerIterator { - - private final BigDecimal x; - - private final MathContext mathContext; - - private BigDecimal powerOfX; - - public PowerNIterator(BigDecimal x, MathContext mathContext) { - this.x = x; - this.mathContext = mathContext; - - powerOfX = BigDecimal.ONE; - } - - @Override - public BigDecimal getCurrentPower() { - return powerOfX; - } - - @Override - public void calculateNextPower() { - powerOfX = powerOfX.multiply(x, mathContext); - } -} \ No newline at end of file diff --git a/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNIterator.java b/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNIterator.java deleted file mode 100644 index 839d617e16..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNIterator.java +++ /dev/null @@ -1,33 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -/** - * {@link PowerIterator} to calculate x2*n. - */ -public class PowerTwoNIterator implements PowerIterator { - - private final MathContext mathContext; - - private final BigDecimal xPowerTwo; - - private BigDecimal powerOfX; - - public PowerTwoNIterator(BigDecimal x, MathContext mathContext) { - this.mathContext = mathContext; - - xPowerTwo = x.multiply(x, mathContext); - powerOfX = BigDecimal.ONE; - } - - @Override - public BigDecimal getCurrentPower() { - return powerOfX; - } - - @Override - public void calculateNextPower() { - powerOfX = powerOfX.multiply(xPowerTwo, mathContext); - } -} \ No newline at end of file diff --git a/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNMinusOneIterator.java b/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNMinusOneIterator.java deleted file mode 100644 index 15ad0168c0..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNMinusOneIterator.java +++ /dev/null @@ -1,35 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import ch.obermuhlner.math.big.BigDecimalMath; - -import java.math.BigDecimal; -import java.math.MathContext; - -/** - * {@link PowerIterator} to calculate x2*n-1. - */ -public class PowerTwoNMinusOneIterator implements PowerIterator { - - private final MathContext mathContext; - - private final BigDecimal xPowerTwo; - - private BigDecimal powerOfX; - - public PowerTwoNMinusOneIterator(BigDecimal x, MathContext mathContext) { - this.mathContext = mathContext; - - xPowerTwo = x.multiply(x, mathContext); - powerOfX = BigDecimalMath.reciprocal(x, mathContext); - } - - @Override - public BigDecimal getCurrentPower() { - return powerOfX; - } - - @Override - public void calculateNextPower() { - powerOfX = powerOfX.multiply(xPowerTwo, mathContext); - } -} \ No newline at end of file diff --git a/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNPlusOneIterator.java b/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNPlusOneIterator.java deleted file mode 100644 index 57afa97634..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/PowerTwoNPlusOneIterator.java +++ /dev/null @@ -1,33 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -/** - * {@link PowerIterator} to calculate x2*n+1. - */ -public class PowerTwoNPlusOneIterator implements PowerIterator { - - private final MathContext mathContext; - - private final BigDecimal xPowerTwo; - - private BigDecimal powerOfX; - - public PowerTwoNPlusOneIterator(BigDecimal x, MathContext mathContext) { - this.mathContext = mathContext; - - xPowerTwo = x.multiply(x, mathContext); - powerOfX = x; - } - - @Override - public BigDecimal getCurrentPower() { - return powerOfX; - } - - @Override - public void calculateNextPower() { - powerOfX = powerOfX.multiply(xPowerTwo, mathContext); - } -} \ No newline at end of file diff --git a/src/main/java/ch/obermuhlner/math/big/internal/SeriesCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/SeriesCalculator.java deleted file mode 100644 index 117c2737d2..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/SeriesCalculator.java +++ /dev/null @@ -1,127 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import ch.obermuhlner.math.big.BigRational; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.ArrayList; -import java.util.List; - -import static java.util.Objects.requireNonNull; - -/** - * Utility class to calculate taylor series efficiently until the maximum error (as defined by the precision in the {@link MathContext} is reached. - * - *

Stores the factors of the taylor series terms so that future calculations will be faster.

- */ -public abstract class SeriesCalculator { - - private final boolean calculateInPairs; - - private final List factors = new ArrayList<>(); - - /** - * Constructs a {@link SeriesCalculator} that calculates single terms. - */ - protected SeriesCalculator() { - this(false); - } - - /** - * Constructs a {@link SeriesCalculator} with control over whether the sum terms are calculated in pairs. - * - *

Calculation of pairs is useful for taylor series where the terms alternate the sign. - * In these cases it is more efficient to calculate two terms at once check then whether the acceptable error has been reached.

- * - * @param calculateInPairs true to calculate the terms in pairs, false to calculate single terms - */ - protected SeriesCalculator(boolean calculateInPairs) { - this.calculateInPairs = calculateInPairs; - } - - /** - * Calculates the series for the specified value x and the precision defined in the {@link MathContext}. - * - * @param x the value x - * @param mathContext the {@link MathContext} - * @return the calculated result - */ - public BigDecimal calculate(BigDecimal x, MathContext mathContext) { - BigDecimal acceptableError = BigDecimal.ONE.movePointLeft(mathContext.getPrecision() + 1); - - PowerIterator powerIterator = createPowerIterator(x, mathContext); - - BigDecimal sum = BigDecimal.ZERO; - BigDecimal step; - int i = 0; - do { - BigRational factor; - BigDecimal xToThePower; - - factor = getFactor(i); - xToThePower = powerIterator.getCurrentPower(); - powerIterator.calculateNextPower(); - step = factor.getNumerator().multiply(xToThePower).divide(factor.getDenominator(), mathContext); - i++; - - if (calculateInPairs) { - factor = getFactor(i); - xToThePower = powerIterator.getCurrentPower(); - powerIterator.calculateNextPower(); - BigDecimal step2 = factor.getNumerator().multiply(xToThePower).divide(factor.getDenominator(), mathContext); - step = step.add(step2); - i++; - } - - sum = sum.add(step); - //System.out.println(sum + " " + step); - } while (step.abs().compareTo(acceptableError) > 0); - - return sum.round(mathContext); - } - - /** - * Creates the {@link PowerIterator} used for this series. - * - * @param x the value x - * @param mathContext the {@link MathContext} - * @return the {@link PowerIterator} - */ - protected abstract PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext); - - /** - * Returns the factor of the term with specified index. - * - * All mutable state of this class (and all its subclasses) must be modified in this method. - * This method is synchronized to allow thread-safe usage of this class. - * - * @param index the index (starting with 0) - * @return the factor of the specified term - */ - protected synchronized BigRational getFactor(int index) { - while (factors.size() <= index) { - BigRational factor = getCurrentFactor(); - addFactor(factor); - calculateNextFactor(); - } - return factors.get(index); - } - - private void addFactor(BigRational factor){ - factors.add(requireNonNull(factor, "Factor cannot be null")); - } - - /** - * Returns the factor of the highest term already calculated. - *

When called for the first time will return the factor of the first term (index 0).

- *

After this call the method {@link #calculateNextFactor()} will be called to prepare for the next term.

- * - * @return the factor of the highest term - */ - protected abstract BigRational getCurrentFactor(); - - /** - * Calculates the factor of the next term. - */ - protected abstract void calculateNextFactor(); -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/SinCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/SinCalculator.java deleted file mode 100644 index 471074fd6b..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/SinCalculator.java +++ /dev/null @@ -1,49 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -import ch.obermuhlner.math.big.BigRational; - -/** - * Calculates sinus using the Maclaurin series. - * - *

See Wikipedia: Taylorreihe

- * - *

No argument checking or optimizations are done. - * This implementation is not intended to be called directly.

- */ -public class SinCalculator extends SeriesCalculator { - - public static final SinCalculator INSTANCE = new SinCalculator(); - - private int n = 0; - private boolean negative = false; - private BigRational factorial2nPlus1 = BigRational.ONE; - - private SinCalculator() { - super(true); - } - - @Override - protected BigRational getCurrentFactor() { - BigRational factor = factorial2nPlus1.reciprocal(); - if (negative) { - factor = factor.negate(); - } - return factor; - } - - @Override - protected void calculateNextFactor() { - n++; - factorial2nPlus1 = factorial2nPlus1.multiply(2 * n); - factorial2nPlus1 = factorial2nPlus1.multiply(2 * n + 1); - negative = !negative; - } - - @Override - protected PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext) { - return new PowerTwoNPlusOneIterator(x, mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/internal/SinhCalculator.java b/src/main/java/ch/obermuhlner/math/big/internal/SinhCalculator.java deleted file mode 100644 index 9601735755..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/internal/SinhCalculator.java +++ /dev/null @@ -1,44 +0,0 @@ -package ch.obermuhlner.math.big.internal; - -import java.math.BigDecimal; -import java.math.MathContext; - -import ch.obermuhlner.math.big.BigRational; - -/** - * Calculates sinus hyperbolicus using the Taylor series. - * - *

See Wikipedia: Taylor series

- * - *

No argument checking or optimizations are done. - * This implementation is not intended to be called directly.

- */ -public class SinhCalculator extends SeriesCalculator { - - public static final SinhCalculator INSTANCE = new SinhCalculator(); - - private int n = 0; - - private BigRational factorial2nPlus1 = BigRational.ONE; - - private SinhCalculator() { - super(true); - } - - @Override - protected BigRational getCurrentFactor() { - return factorial2nPlus1.reciprocal(); - } - - @Override - protected void calculateNextFactor() { - n++; - factorial2nPlus1 = factorial2nPlus1.multiply(2 * n); - factorial2nPlus1 = factorial2nPlus1.multiply(2 * n + 1); - } - - @Override - protected PowerIterator createPowerIterator(BigDecimal x, MathContext mathContext) { - return new PowerTwoNPlusOneIterator(x, mathContext); - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/stream/BigDecimalStream.java b/src/main/java/ch/obermuhlner/math/big/stream/BigDecimalStream.java deleted file mode 100644 index 05a45fd846..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/stream/BigDecimalStream.java +++ /dev/null @@ -1,219 +0,0 @@ -package ch.obermuhlner.math.big.stream; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Comparator; -import java.util.Spliterator; -import java.util.Spliterators.AbstractSpliterator; -import java.util.function.Consumer; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import ch.obermuhlner.math.big.BigDecimalMath; - -/** - * Provides constructor methods for streams of {@link BigDecimal} elements. - */ -public class BigDecimalStream { - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endExclusive} (exclusive) by an incremental {@code step}. - * - *

An equivalent sequence of increasing values can be produced - * sequentially using a {@code for} loop as follows: - *

for (BigDecimal i = startInclusive; i.compareTo(endExclusive) < 0; i = i.add(step, mathContext)) {
-    // ...
-}
- * - * @param startInclusive the (inclusive) initial value - * @param endExclusive the exclusive upper bound - * @param step the step between elements - * @param mathContext the {@link MathContext} used for all mathematical operations - * @return a sequential {@code Stream} - */ - public static Stream range(BigDecimal startInclusive, BigDecimal endExclusive, BigDecimal step, MathContext mathContext) { - if (step.signum() == 0) { - throw new IllegalArgumentException("invalid step: 0"); - } - if (endExclusive.subtract(startInclusive).signum() != step.signum()) { - return Stream.empty(); - } - return StreamSupport.stream(new BigDecimalSpliterator(startInclusive, endExclusive, false, step, mathContext), false); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endExclusive} (exclusive) by an incremental {@code step}. - * - *

The {@code long} arguments are converted using {@link BigDecimal#valueOf(long)}.

- * - * @param startInclusive the (inclusive) initial value - * @param endExclusive the exclusive upper bound - * @param step the step between elements - * @param mathContext the {@link MathContext} used for all mathematical operations - * @return a sequential {@code Stream} - * @see #range(BigDecimal, BigDecimal, BigDecimal, MathContext) - */ - public static Stream range(long startInclusive, long endExclusive, long step, MathContext mathContext) { - return range(BigDecimal.valueOf(startInclusive), BigDecimal.valueOf(endExclusive), BigDecimal.valueOf(step), mathContext); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endExclusive} (exclusive) by an incremental {@code step}. - * - *

The {@code double} arguments are converted using {@link BigDecimal#valueOf(double)}.

- * - * @param startInclusive the (inclusive) initial value - * @param endExclusive the exclusive upper bound - * @param step the step between elements - * @param mathContext the {@link MathContext} used for all mathematical operations - * @return a sequential {@code Stream} - * @see #range(BigDecimal, BigDecimal, BigDecimal, MathContext) - */ - public static Stream range(double startInclusive, double endExclusive, double step, MathContext mathContext) { - return range(BigDecimal.valueOf(startInclusive), BigDecimal.valueOf(endExclusive), BigDecimal.valueOf(step), mathContext); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endInclusive} (inclusive) by an incremental {@code step}. - * - *

An equivalent sequence of increasing values can be produced - * sequentially using a {@code for} loop as follows: - *

for (BigDecimal i = startInclusive; i.compareTo(endInclusive) <= 0; i = i.add(step, mathContext)) {
-    // ...
-}
- * - * @param startInclusive the (inclusive) initial value - * @param endInclusive the inclusive upper bound - * @param step the step between elements - * @param mathContext the {@link MathContext} used for all mathematical operations - * @return a sequential {@code Stream} - * @see #range(BigDecimal, BigDecimal, BigDecimal, MathContext) - */ - public static Stream rangeClosed(BigDecimal startInclusive, BigDecimal endInclusive, BigDecimal step, MathContext mathContext) { - if (step.signum() == 0) { - throw new IllegalArgumentException("invalid step: 0"); - } - if (endInclusive.subtract(startInclusive).signum() == -step.signum()) { - return Stream.empty(); - } - return StreamSupport.stream(new BigDecimalSpliterator(startInclusive, endInclusive, true, step, mathContext), false); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endInclusive} (inclusive) by an incremental {@code step}. - * - *

The {@code long} arguments are converted using {@link BigDecimal#valueOf(long)}.

- * - * @param startInclusive the (inclusive) initial value - * @param endInclusive the inclusive upper bound - * @param step the step between elements - * @param mathContext the {@link MathContext} used for all mathematical operations - * @return a sequential {@code Stream} - * @see #rangeClosed(BigDecimal, BigDecimal, BigDecimal, MathContext) - */ - public static Stream rangeClosed(long startInclusive, long endInclusive, long step, MathContext mathContext) { - return rangeClosed(BigDecimal.valueOf(startInclusive), BigDecimal.valueOf(endInclusive), BigDecimal.valueOf(step), mathContext); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endInclusive} (inclusive) by an incremental {@code step}. - * - *

The {@code double} arguments are converted using {@link BigDecimal#valueOf(double)}.

- * - * @param startInclusive the (inclusive) initial value - * @param endInclusive the inclusive upper bound - * @param step the step between elements - * @param mathContext the {@link MathContext} used for all mathematical operations - * @return a sequential {@code Stream} - * @see #rangeClosed(BigDecimal, BigDecimal, BigDecimal, MathContext) - */ - public static Stream rangeClosed(double startInclusive, double endInclusive, double step, MathContext mathContext) { - return rangeClosed(BigDecimal.valueOf(startInclusive), BigDecimal.valueOf(endInclusive), BigDecimal.valueOf(step), mathContext); - } - - private static class BigDecimalSpliterator extends AbstractSpliterator { - - private BigDecimal value; - private BigDecimal step; - private long count; - private MathContext mathContext; - - public BigDecimalSpliterator(BigDecimal startInclusive, BigDecimal step, long count, MathContext mathContext) { - super(count, - Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED | Spliterator.SORTED); - - this.value = startInclusive; - this.step = step; - this.count = count; - this.mathContext = mathContext; - } - - public BigDecimalSpliterator(BigDecimal startInclusive, BigDecimal end, boolean inclusive, BigDecimal step, MathContext mathContext) { - this(startInclusive, step, estimatedCount(startInclusive, end, inclusive, step, mathContext), mathContext); - } - - private static long estimatedCount(BigDecimal startInclusive, BigDecimal end, boolean inclusive, BigDecimal step, MathContext mathContext) { - BigDecimal count = end.subtract(startInclusive).divide(step, mathContext); - long result = count.longValue(); - if (BigDecimalMath.fractionalPart(count).signum() != 0) { - result++; - } else { - if (inclusive) { - result++; - } - } - return result; - } - - @Override - public Comparator getComparator() { - if (step.signum() < 0) { - return Comparator.reverseOrder(); - } - return null; - } - - @Override - public boolean tryAdvance(Consumer action) { - if (count == 0) { - return false; - } - - action.accept(value); - value = value.add(step, mathContext); - count--; - return true; - } - - @Override - public void forEachRemaining(Consumer action) { - while (count > 0) { - action.accept(value); - value = value.add(step, mathContext); - count--; - } - } - - @Override - public Spliterator trySplit() { - long firstHalfCount = count / 2; - - if (firstHalfCount == 0) { - return null; - } - - long secondHalfCount = count - firstHalfCount; - - count = firstHalfCount; - BigDecimal startSecondHalf = value.add(step.multiply(new BigDecimal(firstHalfCount), mathContext), mathContext); - - return new BigDecimalSpliterator(startSecondHalf, step, secondHalfCount, mathContext); - } - } -} diff --git a/src/main/java/ch/obermuhlner/math/big/stream/BigFloatStream.java b/src/main/java/ch/obermuhlner/math/big/stream/BigFloatStream.java deleted file mode 100644 index 1c982302a6..0000000000 --- a/src/main/java/ch/obermuhlner/math/big/stream/BigFloatStream.java +++ /dev/null @@ -1,214 +0,0 @@ -package ch.obermuhlner.math.big.stream; - -import java.util.Comparator; -import java.util.Spliterator; -import java.util.Spliterators.AbstractSpliterator; -import java.util.function.Consumer; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import ch.obermuhlner.math.big.BigFloat; -import ch.obermuhlner.math.big.BigFloat.Context; - -/** - * Provides constructor methods for streams of {@link BigFloat} elements. - */ -public class BigFloatStream { - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endExclusive} (exclusive) by an incremental {@code step}. - * - *

An equivalent sequence of increasing values can be produced - * sequentially using a {@code for} loop as follows: - *

for (BigFloat i = startInclusive; i.isLessThan(endExclusive); i = i.add(step)) {
-    // ...
-}
- * - * @param startInclusive the (inclusive) initial value - * @param endExclusive the exclusive upper bound - * @param step the step between elements - * @return a sequential {@code Stream} - */ - public static Stream range(BigFloat startInclusive, BigFloat endExclusive, BigFloat step) { - if (step.isZero()) { - throw new IllegalArgumentException("invalid step: 0"); - } - if (endExclusive.subtract(startInclusive).signum() != step.signum()) { - return Stream.empty(); - } - return StreamSupport.stream(new BigFloatSpliterator(startInclusive, endExclusive, false, step), false); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endExclusive} (exclusive) by an incremental {@code step}. - * - *

{@link Context#valueOf(long)} is used to convert the {@code long} values.

- * - * @param startInclusive the (inclusive) initial value - * @param endExclusive the exclusive upper bound - * @param step the step between elements - * @param context the {@link Context} used to convert the {@code long} values - * @return a sequential {@code Stream} - * @see #range(BigFloat, BigFloat, BigFloat) - */ - public static Stream range(long startInclusive, long endExclusive, long step, Context context) { - return range(context.valueOf(startInclusive), context.valueOf(endExclusive), context.valueOf(step)); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endExclusive} (exclusive) by an incremental {@code step}. - * - *

{@link Context#valueOf(double)} is used to convert the {@code double} values.

- * - * @param startInclusive the (inclusive) initial value - * @param endExclusive the exclusive upper bound - * @param step the step between elements - * @param context the {@link Context} used to convert the {@code double} values - * @return a sequential {@code Stream} - * @see #range(BigFloat, BigFloat, BigFloat) - */ - public static Stream range(double startInclusive, double endExclusive, double step, Context context) { - return range(context.valueOf(startInclusive), context.valueOf(endExclusive), context.valueOf(step)); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endInclusive} (inclusive) by an incremental {@code step}. - * - *

An equivalent sequence of increasing values can be produced - * sequentially using a {@code for} loop as follows: - *

for (BigFloat i = startInclusive; i.isLessThanOrEqual(endInclusive); i = i.add(step)) {
-    //...
-}
-
- * - * @param startInclusive the (inclusive) initial value - * @param endInclusive the inclusive upper bound - * @param step the step between elements - * @return a sequential {@code Stream} - */ - public static Stream rangeClosed(BigFloat startInclusive, BigFloat endInclusive, BigFloat step) { - if (step.isZero()) { - throw new IllegalArgumentException("invalid step: 0"); - } - if (endInclusive.subtract(startInclusive).signum() == -step.signum()) { - return Stream.empty(); - } - return StreamSupport.stream(new BigFloatSpliterator(startInclusive, endInclusive, true, step), false); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endInclusive} (inclusive) by an incremental {@code step}. - * - *

{@link Context#valueOf(long)} is used to convert the {@code long} values.

- * - * @param startInclusive the (inclusive) initial value - * @param endInclusive the inclusive upper bound - * @param step the step between elements - * @param context the {@link Context} used to convert the {@code long} values - * @return a sequential {@code Stream} - * @see #rangeClosed(BigFloat, BigFloat, BigFloat) - */ - public static Stream rangeClosed(long startInclusive, long endInclusive, long step, Context context) { - return rangeClosed(context.valueOf(startInclusive), context.valueOf(endInclusive), context.valueOf(step)); - } - - /** - * Returns a sequential ordered {@code Stream} from {@code startInclusive} - * (inclusive) to {@code endInclusive} (inclusive) by an incremental {@code step}. - * - *

{@link Context#valueOf(double)} is used to convert the {@code double} values.

- * - * @param startInclusive the (inclusive) initial value - * @param endInclusive the inclusive upper bound - * @param step the step between elements - * @param context the {@link Context} used to convert the {@code double} values - * @return a sequential {@code Stream} - * @see #rangeClosed(BigFloat, BigFloat, BigFloat) - */ - public static Stream rangeClosed(double startInclusive, double endInclusive, double step, Context context) { - return rangeClosed(context.valueOf(startInclusive), context.valueOf(endInclusive), context.valueOf(step)); - } - - private static class BigFloatSpliterator extends AbstractSpliterator { - - private BigFloat value; - private BigFloat step; - private long count; - - public BigFloatSpliterator(BigFloat startInclusive, BigFloat step, long count) { - super(count, - Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED | Spliterator.SORTED); - - this.value = startInclusive; - this.step = step; - this.count = count; - } - - public BigFloatSpliterator(BigFloat startInclusive, BigFloat end, boolean inclusive, BigFloat step) { - this(startInclusive, step, estimatedCount(startInclusive, end, inclusive, step)); - } - - private static long estimatedCount(BigFloat startInclusive, BigFloat end, boolean inclusive, BigFloat step) { - BigFloat count = end.subtract(startInclusive).divide(step); - long result = count.toLong(); - if (count.getFractionalPart().signum() != 0) { - result++; - } else { - if (inclusive) { - result++; - } - } - return result; - } - - @Override - public Comparator getComparator() { - if (step.signum() < 0) { - return Comparator.reverseOrder(); - } - return null; - } - - @Override - public boolean tryAdvance(Consumer action) { - if (count == 0) { - return false; - } - - action.accept(value); - value = value.add(step); - count--; - return true; - } - - @Override - public void forEachRemaining(Consumer action) { - while (count > 0) { - action.accept(value); - value = value.add(step); - count--; - } - } - - @Override - public Spliterator trySplit() { - long firstHalfCount = count / 2; - - if (firstHalfCount == 0) { - return null; - } - - long secondHalfCount = count - firstHalfCount; - - count = firstHalfCount; - BigFloat startSecondHalf = value.add(step.multiply(firstHalfCount)); - - return new BigFloatSpliterator(startSecondHalf, step, secondHalfCount); - } - } -} -- cgit