All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.obermuhlner.math.big.BigDecimalMath Maven / Gradle / Ivy

There is a newer version: 2.3.2
Show newest version
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 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 LOG_TWO = new BigDecimal("0.69314718055994530941723212145817656807550013436025525412068000949339362196969471560586332699641868754200148102057068573368552023575813055703267075163507596193072757082837143519030703862389167347112335011536449795523912047517268157493206515552473413952588295045300709532636664265410423915781495204374043038550080194417064167151864471283996817178454695702627163106454615025720740248163777338963855069526066834113727387372292895649354702576265209885969320196505855476470330679365443254763274495125040606943814710468994650622016772042452452961268794654619316517468139267250410380254625965686914419287160829380317271436778265487756648508567407764845146443994046142260319309673540257444607030809608504748663852313818167675143866747664789088143714198549423151997354880375165861275352916610007105355824987941472950929311389715599820565439287170007218085761025236889213244971389320378439353088774825970171559107088236836275898425891853530243634214367061189236789192372314672321720534016492568727477823445353476481149418642386776774406069562657379600867076257199184734022651462837904883062033061144630073719489");
	private static final BigDecimal LOG_THREE = new BigDecimal("1.0986122886681096913952452369225257046474905578227494517346943336374942932186089668736157548137320887879700290659578657423680042259305198210528018707672774106031627691833813671793736988443609599037425703167959115211455919177506713470549401667755802222031702529468975606901065215056428681380363173732985777823669916547921318181490200301038236301222486527481982259910974524908964580534670088459650857484441190188570876474948670796130858294116021661211840014098255143919487688936798494302255731535329685345295251459213876494685932562794416556941578272310355168866102118469890439943063138255285736466882824988136822800634143910786893251456437510204451627561934973982116941585740535361758900975122233797736969687754354795135712982177017581242122351405810163272465588937249564919185242960796684234647069377237252655082032078333928055892853146873095132606458309184397496822230325765467533311823019649275257599132217851353390237482964339502546074245824934666866121881436526565429542767610505477795422933973323401173743193974579847018559548494059478353943841010602930762292228131207489306344534025277732685627");
	private static final BigDecimal LOG_TEN = new BigDecimal("2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058498078280597511938544450099781311469159346662410718466923101075984383191913");

	private static final BigDecimal PI = new BigDecimal("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315");                               
	
	private static final BigDecimal ROUGHLY_TWO_PI = new BigDecimal("3.141592653589793").multiply(TWO);
	
	private static final int EXPECTED_INITIAL_PRECISION = 17;
	
	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 BigDecimalMath() {
		// prevent instances
	}

	/**
	 * Returns whether the specified {@link BigDecimal} value can be represented as int without loss of precision.
	 * 
	 * 

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 without loss of precision */ public static boolean isIntValue(BigDecimal value) { // TODO impl isIntValue() without exceptions try { value.intValueExact(); return true; } catch (ArithmeticException ex) { // ignored } return false; } /** * 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 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)); } /** * Calculates the factorial of the specified {@link BigDecimal}. * *

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]; for (int i = factorialCache.length; i <= n; i++) { result = result.multiply(valueOf(i)); } return result; } /** * 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 */ 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 */ public static BigDecimal pow(BigDecimal x, BigDecimal y, MathContext mathContext) { // x^y = exp(y*log(x)) if (x.signum() == 0) { switch (y.signum()) { case 0 : return ONE; case 1 : return ZERO; } } try { int intValue = y.intValueExact(); return pow(x, intValue, mathContext); } catch (ArithmeticException ex) { // ignored } MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = exp(y.multiply(log(x, mc), mc), mc); return result.round(mathContext); } /** * Calculates {@link BigDecimal} x to the power of int 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 int 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 BigDecimal pow(BigDecimal x, int y, MathContext mathContext) { if (y < 0) { return ONE.divide(pow(x, -y, mathContext), mathContext); } MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); 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 result.round(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 */ public static BigDecimal sqrt(BigDecimal x, MathContext 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() + 4; BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1); BigDecimal result = BigDecimal.valueOf(Math.sqrt(x.doubleValue())); int adaptivePrecision = EXPECTED_INITIAL_PRECISION; BigDecimal last; do { last = result; adaptivePrecision = adaptivePrecision * 3; if (adaptivePrecision > maxPrecision) { adaptivePrecision = maxPrecision; } MathContext mc = new MathContext(adaptivePrecision, mathContext.getRoundingMode()); result = x.divide(result, mc).add(last, mc).divide(TWO, mc); } while (adaptivePrecision < maxPrecision || result.subtract(last).abs().compareTo(acceptableError) > 0); return result.round(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 */ public static BigDecimal root(BigDecimal x, BigDecimal n, MathContext 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 = adaptivePrecision * 3; if (adaptivePrecision > maxPrecision) { adaptivePrecision = maxPrecision; } MathContext mc = new MathContext(adaptivePrecision, mathContext.getRoundingMode()); step = x.divide(pow(result, nMinus1, mc), mc).subtract(result, mc).divide(n, mc); result = result.add(step, mc); } while (adaptivePrecision < maxPrecision || step.abs().compareTo(acceptableError) > 0); return result.round(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 */ public static BigDecimal log(BigDecimal x, MathContext mathContext) { // http://en.wikipedia.org/wiki/Natural_logarithm 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 result.round(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 */ public static BigDecimal log2(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); BigDecimal result = log(x, mc).divide(logTwo(mc), mc); return result.round(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 */ public static BigDecimal log10(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 2, mathContext.getRoundingMode()); BigDecimal result = log(x, mc).divide(logTen(mc), mc); return result.round(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() + 4; BigDecimal acceptableError = ONE.movePointLeft(mathContext.getPrecision() + 1); BigDecimal result = BigDecimal.valueOf(Math.log(x.doubleValue())); int adaptivePrecision = EXPECTED_INITIAL_PRECISION; BigDecimal step; do { adaptivePrecision = 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, mc), mc).divide(x.add(expY, mc), mc); result = result.add(step); } while (adaptivePrecision < maxPrecision || step.abs().compareTo(acceptableError) > 0); return result; } private static BigDecimal logUsingTwoThree(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); 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 *= 2; } } 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 *= 2; } } BigDecimal correctedX = x; BigDecimal result = ZERO; if (factorOfTwo > 0) { correctedX = correctedX.divide(valueOf(powerOfTwo), mc); result = result.add(logTwo(mc).multiply(valueOf(factorOfTwo), mc), mc); } else if (factorOfTwo < 0) { correctedX = correctedX.multiply(valueOf(powerOfTwo), mc); result = result.subtract(logTwo(mc).multiply(valueOf(-factorOfTwo), mc), mc); } if (factorOfThree > 0) { correctedX = correctedX.divide(valueOf(powerOfThree), mc); result = result.add(logThree(mc).multiply(valueOf(factorOfThree), mc), mc); } else if (factorOfThree < 0) { correctedX = correctedX.multiply(valueOf(powerOfThree), mc); result = result.subtract(logThree(mc).multiply(valueOf(-factorOfThree), mc), mc); } result = result.add(logUsingNewton(correctedX, mc)); return result; } private static BigDecimal logUsingExponent(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); int exponent = exponent(x); BigDecimal mantissa = mantissa(x); BigDecimal result = logUsingTwoThree(mantissa, mc); if (exponent != 0) { result = result.add(valueOf(exponent).multiply(logTen(mc), 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 */ public static BigDecimal pi(MathContext mathContext) { if (mathContext.getPrecision() < PI.precision()) { return PI.round(mathContext); } return piChudnovski(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 pi.round(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 */ public static BigDecimal e(MathContext mathContext) { return exp(ONE, mathContext); } private static BigDecimal logTen(MathContext mathContext) { if (mathContext.getPrecision() < LOG_TEN.precision()) { return LOG_TEN; } return logUsingNewton(BigDecimal.TEN, mathContext); } private static BigDecimal logTwo(MathContext mathContext) { if (mathContext.getPrecision() < LOG_TWO.precision()) { return LOG_TWO; } return logUsingNewton(TWO, mathContext); } private static BigDecimal logThree(MathContext mathContext) { if (mathContext.getPrecision() < LOG_THREE.precision()) { return LOG_THREE; } return logUsingNewton(THREE, 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 */ public static BigDecimal exp(BigDecimal x, MathContext 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() + 9, mathContext.getRoundingMode()); BigDecimal z = ONE.add(fractionalPart.divide(integralPart, mc)); BigDecimal t = expTaylor(z, mc); BigDecimal result = pow(t, integralPart.intValue(), mc); return result.round(mathContext); } private static BigDecimal expTaylor(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); x = x.divide(valueOf(256), mc); BigDecimal result = ExpCalculator.INSTANCE.calculate(x, mc); result = BigDecimalMath.pow(result, 256, mc); return result.round(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 */ public static BigDecimal sin(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); if (x.abs().compareTo(ROUGHLY_TWO_PI) > 0) { BigDecimal twoPi = TWO.multiply(pi(mc), mc); x = x.remainder(twoPi, mc); } BigDecimal result = SinCalculator.INSTANCE.calculate(x, mc); return result.round(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 */ public static BigDecimal asin(BigDecimal x, MathContext 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), mc), mc); return acos(xTransformed, mathContext); } BigDecimal result = AsinCalculator.INSTANCE.calculate(x, mc); return result.round(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} */ public static BigDecimal cos(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); if (x.abs().compareTo(ROUGHLY_TWO_PI) > 0) { BigDecimal twoPi = TWO.multiply(pi(mc), mc); x = x.remainder(twoPi, mc); } BigDecimal result = CosCalculator.INSTANCE.calculate(x, mc); return result.round(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 */ public static BigDecimal acos(BigDecimal x, MathContext 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), mc); return result.round(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 */ public static BigDecimal tan(BigDecimal x, MathContext mathContext) { if (x.signum() == 0) { return ZERO; } 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 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 */ public static BigDecimal atan(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); x = x.divide(sqrt(ONE.add(x.multiply(x, mc), mc), mc), mc); BigDecimal result = asin(x, mc); return result.round(mathContext); } /** * 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 */ public static BigDecimal cot(BigDecimal x, MathContext 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).round(mathContext); return result.round(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 */ public static BigDecimal acot(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); BigDecimal result = pi(mc).divide(TWO, mc).subtract(atan(x, mc), mc); return result.round(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 */ public static BigDecimal sinh(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); BigDecimal result = SinhCalculator.INSTANCE.calculate(x, mc); return result.round(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 */ public static BigDecimal cosh(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); BigDecimal result = CoshCalculator.INSTANCE.calculate(x, mc); return result.round(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 */ public static BigDecimal tanh(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = sinh(x, mc).divide(cosh(x, mc), mc); return result.round(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 */ public static BigDecimal coth(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = cosh(x, mc).divide(sinh(x, mc), mc); return result.round(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 */ public static BigDecimal asinh(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = log(x.add(sqrt(x.multiply(x, mc).add(ONE, mc), mc), mc), mc); return result.round(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 */ public static BigDecimal acosh(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = log(x.add(sqrt(x.multiply(x, mc).subtract(ONE, mc), mc), mc), mc); return result.round(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 tanges 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 */ public static BigDecimal atanh(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = log(ONE.add(x, mc).divide(ONE.subtract(x, mc), mc), mc).divide(TWO, mc); return result.round(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 */ public static BigDecimal acoth(BigDecimal x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 6, mathContext.getRoundingMode()); BigDecimal result = log(x.add(ONE, mc).divide(x.subtract(ONE, mc), mc), mc).divide(TWO, mc); return result.round(mathContext); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy