/** * Returns a new {@code BigDecimal} whose value is {@code this * * multiplicand}. The result is rounded according to the passed context * {@code mc}. * * @param multiplicand * value to be multiplied with {@code this}. * @param mc * rounding mode and precision for the result of this operation. * @return {@code this * multiplicand}. * @throws NullPointerException * if {@code multiplicand == null} or {@code mc == null}. */ public static BigDecimal Multiply(BigDecimal value, BigDecimal multiplicand, MathContext mc) { BigDecimal result = Multiply(value, multiplicand); result.InplaceRound(mc); return(result); }
/** * Returns a new {@code BigDecimal} whose value is {@code this % divisor}. * <p> * The remainder is defined as {@code this - * this.divideToIntegralValue(divisor) * divisor}. * <p> * The specified rounding mode {@code mc} is used for the division only. * * @param divisor * value by which {@code this} is divided. * @param mc * rounding mode and precision to be used. * @return {@code this % divisor}. * @throws NullPointerException * if {@code divisor == null}. * @throws ArithmeticException * if {@code divisor == 0}. * @throws ArithmeticException * if {@code mc.getPrecision() > 0} and the result of {@code * this.divideToIntegralValue(divisor, mc)} requires more digits * to be represented. */ public static BigDecimal Remainder(BigDecimal a, BigDecimal b, MathContext context) { BigDecimal remainder; DivideAndRemainder(a, b, context, out remainder); return(remainder); }
/** * Returns a {@code BigDecimal} array which contains the integral part of * {@code this / divisor} at index 0 and the remainder {@code this % * divisor} at index 1. The quotient is rounded down towards zero to the * next integer. The rounding mode passed with the parameter {@code mc} is * not considered. But if the precision of {@code mc > 0} and the integral * part requires more digits, then an {@code ArithmeticException} is thrown. * * @param divisor * value by which {@code this} is divided. * @param mc * math context which determines the maximal precision of the * result. * @return {@code [this.divideToIntegralValue(divisor), * this.remainder(divisor)]}. * @throws NullPointerException * if {@code divisor == null}. * @throws ArithmeticException * if {@code divisor == 0}. * @see #divideToIntegralValue * @see #remainder */ public static BigDecimal DivideAndRemainder(BigDecimal a, BigDecimal b, MathContext context, out BigDecimal remainder) { return(BigDecimalMath.DivideAndRemainder(a, b, context, out remainder)); }
public BigComplex Inverse(MathContext mc) { BigDecimal hyp = Norm(); /* 1/(x+iy)= (x-iy)/(x^2+y^2 */ return(new BigComplex(Real.Divide(hyp, mc), Imaginary.Divide(hyp, mc).Negate())); }
/** * Returns a new {@code BigDecimal} whose value is {@code this}, rounded * according to the passed context {@code mc}. * <p> * If {@code mc.precision = 0}, then no rounding is performed. * <p> * If {@code mc.precision > 0} and {@code mc.roundingMode == UNNECESSARY}, * then an {@code ArithmeticException} is thrown if the result cannot be * represented exactly within the given precision. * * @param mc * rounding mode and precision for the result of this operation. * @return {@code this} rounded according to the passed context. * @throws ArithmeticException * if {@code mc.precision > 0} and {@code mc.roundingMode == * UNNECESSARY} and this cannot be represented within the given * precision. */ public static BigDecimal Round(BigDecimal number, MathContext mc) { var thisBD = new BigDecimal(number.UnscaledValue, number.Scale); thisBD.InplaceRound(mc); return(thisBD); }
public BigComplex Sqrt(MathContext mc) { BigDecimal half = new BigDecimal(2); /* compute l=sqrt(re^2+im^2), then u=sqrt((l+re)/2) * and v= +- sqrt((l-re)/2 as the new real and imaginary parts. */ BigDecimal l = Abs(mc); if (l.CompareTo(BigDecimal.Zero) == 0) { return(new BigComplex(BigMath.ScalePrecision(BigDecimal.Zero, mc), BigMath.ScalePrecision(BigDecimal.Zero, mc))); } BigDecimal u = BigMath.Sqrt(l.Add(Real).Divide(half, mc), mc); BigDecimal v = BigMath.Sqrt(l.Subtract(Real).Divide(half, mc), mc); if (Imaginary.CompareTo(BigDecimal.Zero) >= 0) { return(new BigComplex(u, v)); } else { return(new BigComplex(u, v.Negate())); } }
public BigComplex Multiply(BigComplex oth, MathContext mc) { BigDecimal a = Real.Add(Imaginary).Multiply(oth.Real); BigDecimal b = oth.Real.Add(oth.Imaginary).Multiply(Imaginary); BigDecimal c = oth.Imaginary.Subtract(oth.Real).Multiply(Real); BigDecimal x = a.Subtract(b, mc); BigDecimal y = a.Add(c, mc); return(new BigComplex(x, y)); }
public static BigDecimal Add(BigDecimal value, BigDecimal augend, MathContext mc) { BigDecimal larger; // operand with the largest unscaled value BigDecimal smaller; // operand with the smallest unscaled value BigInteger tempBi; long diffScale = (long)value.Scale - augend.Scale; // Some operand is zero or the precision is infinity if ((augend.IsZero) || (value.IsZero) || (mc.Precision == 0)) { return(BigMath.Round(Add(value, augend), mc)); } // Cases where there is room for optimizations if (value.AproxPrecision() < diffScale - 1) { larger = augend; smaller = value; } else if (augend.AproxPrecision() < -diffScale - 1) { larger = value; smaller = augend; } else { // No optimization is done return(BigMath.Round(Add(value, augend), mc)); } if (mc.Precision >= larger.AproxPrecision()) { // No optimization is done return(BigMath.Round(Add(value, augend), mc)); } // Cases where it's unnecessary to add two numbers with very different scales var largerSignum = larger.Sign; if (largerSignum == smaller.Sign) { tempBi = Multiplication.MultiplyByPositiveInt(larger.UnscaledValue, 10) + BigInteger.FromInt64(largerSignum); } else { tempBi = larger.UnscaledValue - BigInteger.FromInt64(largerSignum); tempBi = Multiplication.MultiplyByPositiveInt(tempBi, 10) + BigInteger.FromInt64(largerSignum * 9); } // Rounding the improved adding larger = new BigDecimal(tempBi, larger.Scale + 1); return(BigMath.Round(larger, mc)); }
public BigDecimal ToBigDecimal(MathContext mc) { /* numerator and denominator individually rephrased */ var n = new BigDecimal(Numerator); var d = new BigDecimal(Denominator); /* the problem with n.divide(d,mc) is that the apparent precision might be * smaller than what is set by mc if the value has a precise truncated representation. * 1/4 will appear as 0.25, independent of mc */ return(BigMath.ScalePrecision(n.Divide(d, mc), mc)); }
public static BigDecimal Pow(BigDecimal number, int n, MathContext mc) { // The ANSI standard X3.274-1996 algorithm int m = System.Math.Abs(n); int mcPrecision = mc.Precision; int elength = (int)System.Math.Log10(m) + 1; // decimal digits in 'n' int oneBitMask; // mask of bits BigDecimal accum; // the single accumulator MathContext newPrecision = mc; // MathContext by default // In particular cases, it reduces the problem to call the other 'pow()' if ((n == 0) || ((number.IsZero) && (n > 0))) { return(Pow(number, n)); } if ((m > 999999999) || ((mcPrecision == 0) && (n < 0)) || ((mcPrecision > 0) && (elength > mcPrecision))) { // math.07=Invalid Operation throw new ArithmeticException(Messages.math07); //$NON-NLS-1$ } if (mcPrecision > 0) { newPrecision = new MathContext(mcPrecision + elength + 1, mc.RoundingMode); } // The result is calculated as if 'n' were positive accum = BigMath.Round(number, newPrecision); oneBitMask = Utils.HighestOneBit(m) >> 1; while (oneBitMask > 0) { accum = BigMath.Multiply(accum, accum, newPrecision); if ((m & oneBitMask) == oneBitMask) { accum = BigMath.Multiply(accum, number, newPrecision); } oneBitMask >>= 1; } // If 'n' is negative, the value is divided into 'ONE' if (n < 0) { accum = Divide(BigDecimal.One, accum, newPrecision); } // The final value is rounded to the destination precision accum.InplaceRound(mc); return(accum); }
public static BigDecimal Subtract(BigDecimal value, BigDecimal subtrahend, MathContext mc) { if (subtrahend == null) { throw new ArgumentNullException("subtrahend"); } if (mc == null) { throw new ArgumentNullException("mc"); } long diffScale = subtrahend.Scale - (long)value.Scale; // Some operand is zero or the precision is infinity if ((subtrahend.IsZero) || (value.IsZero) || (mc.Precision == 0)) { return(BigMath.Round(Subtract(value, subtrahend), mc)); } // Now: this != 0 and subtrahend != 0 if (subtrahend.AproxPrecision() < diffScale - 1) { // Cases where it is unnecessary to subtract two numbers with very different scales if (mc.Precision < value.AproxPrecision()) { var thisSignum = value.Sign; BigInteger tempBI; if (thisSignum != subtrahend.Sign) { tempBI = Multiplication.MultiplyByPositiveInt(value.UnscaledValue, 10) + BigInteger.FromInt64(thisSignum); } else { tempBI = value.UnscaledValue - BigInteger.FromInt64(thisSignum); tempBI = Multiplication.MultiplyByPositiveInt(tempBI, 10) + BigInteger.FromInt64(thisSignum * 9); } // Rounding the improved subtracting var leftOperand = new BigDecimal(tempBI, value.Scale + 1); // it will be only the left operand (this) return(BigMath.Round(leftOperand, mc)); } } // No optimization is done return(BigMath.Round(Subtract(value, subtrahend), mc)); }
public void MathContextConstruction() { String a = "-12380945E+61"; BigDecimal aNumber = BigDecimal.Parse(a); int precision = 6; RoundingMode rm = RoundingMode.HalfDown; MathContext mcIntRm = new MathContext(precision, rm); MathContext mcStr = MathContext.Parse("precision=6 roundingMode=HALFDOWN"); MathContext mcInt = new MathContext(precision); BigDecimal res = BigMath.Abs(aNumber, mcInt); Assert.Equal(res, BigDecimal.Parse("1.23809E+68")); Assert.Equal(mcIntRm, mcStr); Assert.Equal(mcInt.Equals(mcStr), false); Assert.Equal(mcIntRm.GetHashCode(), mcStr.GetHashCode()); Assert.Equal(mcIntRm.ToString(), "precision=6 roundingMode=HalfDown"); }
public void MathContextConstruction() { String a = "-12380945E+61"; BigDecimal aNumber = BigDecimal.Parse(a); int precision = 6; RoundingMode rm = RoundingMode.HalfDown; MathContext mcIntRm = new MathContext(precision, rm); MathContext mcStr = MathContext.Parse("precision=6 roundingMode=HALFDOWN"); MathContext mcInt = new MathContext(precision); BigDecimal res = aNumber.Abs(mcInt); Assert.AreEqual(res, BigDecimal.Parse("1.23809E+68"), "MathContext Constructor with int precision failed"); Assert.AreEqual(mcIntRm, mcStr, "Equal MathContexts are not Equal "); Assert.AreEqual(mcInt.Equals(mcStr), false, "Different MathContext are reported as Equal "); Assert.AreEqual(mcIntRm.GetHashCode(), mcStr.GetHashCode(), "Equal MathContexts have different hashcodes "); Assert.AreEqual(mcIntRm.ToString(), "precision=6 roundingMode=HalfDown", "MathContext.ToString() returning incorrect value"); }
public BigDecimal Abs(MathContext mc) { return(BigMath.Sqrt(Norm(), mc)); }
/** * Returns a new {@code BigDecimal} whose value is the integral part of * {@code this / divisor}. The quotient is rounded down towards zero to the * next integer. The rounding mode passed with the parameter {@code mc} is * not considered. But if the precision of {@code mc > 0} and the integral * part requires more digits, then an {@code ArithmeticException} is thrown. * * @param divisor * value by which {@code this} is divided. * @param mc * math context which determines the maximal precision of the * result. * @return integral part of {@code this / divisor}. * @throws NullPointerException * if {@code divisor == null} or {@code mc == null}. * @throws ArithmeticException * if {@code divisor == 0}. * @throws ArithmeticException * if {@code mc.getPrecision() > 0} and the result requires more * digits to be represented. */ public static BigDecimal DivideToIntegral(BigDecimal a, BigDecimal b, MathContext context) { return(BigDecimalMath.DivideToIntegralValue(a, b, context)); }
public BigComplex Divide(BigComplex oth, MathContext mc) { /* lazy implementation: (x+iy)/(a+ib)= (x+iy)* 1/(a+ib) */ return(Multiply(oth.Inverse(mc), mc)); }
/** * Returns a new {@code BigDecimal} whose value is {@code this ^ n}. The * result is rounded according to the passed context {@code mc}. * <p> * Implementation Note: The implementation is based on the ANSI standard * X3.274-1996 algorithm. * * @param n * exponent to which {@code this} is raised. * @param mc * rounding mode and precision for the result of this operation. * @return {@code this ^ n}. * @throws ArithmeticException * if {@code n < 0} or {@code n > 999999999}. */ public static BigDecimal Pow(BigDecimal number, int exp, MathContext context) { return(BigDecimalMath.Pow(number, exp, context)); }
/** * Returns a new {@code BigDecimal} whose value is the absolute value of * {@code this}. The result is rounded according to the passed context * {@code mc}. * * @param mc * rounding mode and precision for the result of this operation. * @return {@code abs(this)} */ public static BigDecimal Abs(BigDecimal value, MathContext mc) { return(Abs(Round(value, mc))); }
public static BigDecimal DivideAndRemainder(BigDecimal dividend, BigDecimal divisor, MathContext mc, out BigDecimal remainder) { var quotient = DivideToIntegralValue(dividend, divisor, mc); remainder = Subtract(dividend, Multiply(quotient, divisor)); return(quotient); }
public static BigDecimal DivideToIntegralValue(BigDecimal dividend, BigDecimal divisor, MathContext mc) { int mcPrecision = mc.Precision; int diffPrecision = dividend.Precision - divisor.Precision; int lastPow = BigDecimal.TenPow.Length - 1; long diffScale = (long)dividend.Scale - divisor.Scale; long newScale = diffScale; long quotPrecision = diffPrecision - diffScale + 1; BigInteger quotient; BigInteger remainder; // In special cases it call the dual method if ((mcPrecision == 0) || (dividend.IsZero) || (divisor.IsZero)) { return(DivideToIntegralValue(dividend, divisor)); } // Let be: this = [u1,s1] and divisor = [u2,s2] if (quotPrecision <= 0) { quotient = BigInteger.Zero; } else if (diffScale == 0) { // CASE s1 == s2: to calculate u1 / u2 quotient = dividend.UnscaledValue / divisor.UnscaledValue; } else if (diffScale > 0) { // CASE s1 >= s2: to calculate u1 / (u2 * 10^(s1-s2) quotient = dividend.UnscaledValue / (divisor.UnscaledValue * Multiplication.PowerOf10(diffScale)); // To chose 10^newScale to get a quotient with at least 'mc.precision()' digits newScale = System.Math.Min(diffScale, System.Math.Max(mcPrecision - quotPrecision + 1, 0)); // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale quotient = quotient * Multiplication.PowerOf10(newScale); } else { // CASE s2 > s1: /* To calculate the minimum power of ten, such that the quotient * (u1 * 10^exp) / u2 has at least 'mc.precision()' digits. */ long exp = System.Math.Min(-diffScale, System.Math.Max((long)mcPrecision - diffPrecision, 0)); long compRemDiv; // Let be: (u1 * 10^exp) / u2 = [q,r] quotient = BigMath.DivideAndRemainder(dividend.UnscaledValue * Multiplication.PowerOf10(exp), divisor.UnscaledValue, out remainder); newScale += exp; // To fix the scale exp = -newScale; // The remaining power of ten // If after division there is a remainder... if ((remainder.Sign != 0) && (exp > 0)) { // Log10(r) + ((s2 - s1) - exp) > mc.precision ? compRemDiv = (new BigDecimal(remainder)).Precision + exp - divisor.Precision; if (compRemDiv == 0) { // To calculate: (r * 10^exp2) / u2 remainder = (remainder * Multiplication.PowerOf10(exp)) / divisor.UnscaledValue; compRemDiv = System.Math.Abs(remainder.Sign); } if (compRemDiv > 0) { // The quotient won't fit in 'mc.precision()' digits // math.06=Division impossible throw new ArithmeticException(Messages.math06); //$NON-NLS-1$ } } } // Fast return if the quotient is zero if (quotient.Sign == 0) { return(BigDecimal.GetZeroScaledBy(diffScale)); } BigInteger strippedBI = quotient; BigDecimal integralValue = new BigDecimal(quotient); long resultPrecision = integralValue.Precision; int i = 1; // To strip trailing zeros until the specified precision is reached while (!BigInteger.TestBit(strippedBI, 0)) { quotient = BigMath.DivideAndRemainder(strippedBI, BigDecimal.TenPow[i], out remainder); if ((remainder.Sign == 0) && ((resultPrecision - i >= mcPrecision) || (newScale - i >= diffScale))) { resultPrecision -= i; newScale -= i; if (i < lastPow) { i++; } strippedBI = quotient; } else { if (i == 1) { break; } i = 1; } } // To check if the result fit in 'mc.precision()' digits if (resultPrecision > mcPrecision) { // math.06=Division impossible throw new ArithmeticException(Messages.math06); //$NON-NLS-1$ } integralValue.Scale = BigDecimal.ToIntScale(newScale); integralValue.SetUnscaledValue(strippedBI); return(integralValue); }
/** * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. * The result is rounded according to the passed context {@code mc}. If the * passed math context specifies precision {@code 0}, then this call is * equivalent to {@code this.divide(divisor)}. * * @param divisor * value by which {@code this} is divided. * @param mc * rounding mode and precision for the result of this operation. * @return {@code this / divisor}. * @throws NullPointerException * if {@code divisor == null} or {@code mc == null}. * @throws ArithmeticException * if {@code divisor == 0}. * @throws ArithmeticException * if {@code mc.getRoundingMode() == UNNECESSARY} and rounding * is necessary according {@code mc.getPrecision()}. */ public static BigDecimal Divide(BigDecimal a, BigDecimal b, MathContext context) { return(BigDecimalMath.Divide(a, b, context)); }
/// <summary> /// Adds a value to the current instance of <see cref="BigDecimal"/>, /// rounding the result according to the provided context. /// </summary> /// <param name="augend">The value to be added to this instance.</param> /// <param name="mc">The rounding mode and precision for the result of /// this operation.</param> /// <returns> /// Returns a new <see cref="BigDecimal"/> whose value is <c>this + <paramref name="augend"/></c>. /// </returns> /// <exception cref="ArgumentNullException"> /// If the given <paramref name="augend"/> or <paramref name="mc"/> is <c>null</c>. /// </exception> public static BigDecimal Add(BigDecimal value, BigDecimal augend, MathContext mc) { return(BigDecimalMath.Add(value, augend, mc)); }
/// <remarks> /// Returns a new <see cref="BigDecimal"/> whose value is <c>+this</c>. /// </remarks> /// <param name="mc">Rounding mode and precision for the result of this operation.</param> /// <remarks> /// The result is rounded according to the passed context <paramref name="mc"/>. /// </remarks> /// <returns> /// Returns this decimal value rounded. /// </returns> public static BigDecimal Plus(BigDecimal number, MathContext mc) { return(Round(number, mc)); }
/** * Returns a new {@code BigDecimal} whose value is the {@code -this}. The * result is rounded according to the passed context {@code mc}. * * @param mc * rounding mode and precision for the result of this operation. * @return {@code -this} */ public static BigDecimal Negate(BigDecimal number, MathContext mc) { return(Negate(Round(number, mc))); }
public static BigDecimal Divide(BigDecimal dividend, BigDecimal divisor, MathContext mc) { /* Calculating how many zeros must be append to 'dividend' * to obtain a quotient with at least 'mc.precision()' digits */ long traillingZeros = mc.Precision + 2L + divisor.AproxPrecision() - dividend.AproxPrecision(); long diffScale = (long)dividend.Scale - divisor.Scale; long newScale = diffScale; // scale of the final quotient int compRem; // to compare the remainder int i = 1; // index int lastPow = BigDecimal.TenPow.Length - 1; // last power of ten BigInteger integerQuot; // for temporal results BigInteger quotient = dividend.UnscaledValue; BigInteger remainder; // In special cases it reduces the problem to call the dual method if ((mc.Precision == 0) || (dividend.IsZero) || (divisor.IsZero)) { return(Divide(dividend, divisor)); } if (traillingZeros > 0) { // To append trailing zeros at end of dividend quotient = dividend.UnscaledValue * Multiplication.PowerOf10(traillingZeros); newScale += traillingZeros; } quotient = BigMath.DivideAndRemainder(quotient, divisor.UnscaledValue, out remainder); integerQuot = quotient; // Calculating the exact quotient with at least 'mc.precision()' digits if (remainder.Sign != 0) { // Checking if: 2 * remainder >= divisor ? compRem = remainder.ShiftLeftOneBit().CompareTo(divisor.UnscaledValue); // quot := quot * 10 + r; with 'r' in {-6,-5,-4, 0,+4,+5,+6} integerQuot = (integerQuot * BigInteger.Ten) + BigInteger.FromInt64(quotient.Sign * (5 + compRem)); newScale++; } else { // To strip trailing zeros until the preferred scale is reached while (!BigInteger.TestBit(integerQuot, 0)) { quotient = BigMath.DivideAndRemainder(integerQuot, BigDecimal.TenPow[i], out remainder); if ((remainder.Sign == 0) && (newScale - i >= diffScale)) { newScale -= i; if (i < lastPow) { i++; } integerQuot = quotient; } else { if (i == 1) { break; } i = 1; } } } // To perform rounding return(new BigDecimal(integerQuot, BigDecimal.ToIntScale(newScale), mc)); }
/// <summary> /// Subtracts the given value from this instance of <see cref="BigDecimal"/>. /// </summary> /// <remarks> /// <para> /// This overload rounds the result of the operation to the <paramref name="mc">context</paramref> /// provided as argument. /// </para> /// </remarks> /// <param name="subtrahend">The value to be subtracted from this <see cref="BigDecimal"/>.</param> /// <param name="mc">The context used to round the result of this operation.</param> /// <returns> /// Returns an instance of <see cref="BigDecimal"/> that is the result of the /// subtraction of the given <paramref name="subtrahend"/> from this instance. /// </returns> /// <exception cref="ArgumentNullException"> /// If either of the given <paramref name="subtrahend"/> or <paramref name="mc"/> are <c>null</c>. /// </exception> public static BigDecimal Subtract(BigDecimal value, BigDecimal subtrahend, MathContext mc) { return(BigDecimalMath.Subtract(value, subtrahend, mc)); }