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 --- .../core/cElementalDecayResult.java | 41 + .../core/cElementalInstanceStackMap.java | 13 +- .../core/stacks/cElementalInstanceStack.java | 136 +- .../multi/GT_MetaTileEntity_EM_collider.java | 18 +- .../multi/GT_MetaTileEntity_EM_decay.java | 6 +- 26 files changed, 119 insertions(+), 7555 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 create mode 100644 src/main/java/com/github/technus/tectech/mechanics/elementalMatter/core/cElementalDecayResult.java (limited to 'src/main/java') 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.n