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 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)); }