public bool Equals(SqlNumber other) { if (State == NumericState.NegativeInfinity && other.State == NumericState.NegativeInfinity) { return(true); } if (State == NumericState.PositiveInfinity && other.State == NumericState.PositiveInfinity) { return(true); } if (State == NumericState.NotANumber && other.State == NumericState.NotANumber) { return(true); } if (IsNull && other.IsNull) { return(true); } if (IsNull && !other.IsNull) { return(false); } if (!IsNull && other.IsNull) { return(false); } return(innerValue.CompareTo(other.innerValue) == 0); }
public bool Equals(SqlNumber other) { if (state != other.state) { return(false); } if (state != NumericState.None) { return(true); } return(innerValue.CompareTo(other.innerValue) == 0); }
public BigDecimal Get(BigDecimal n) { if (n.CompareTo(ZERO) <= 0) { throw new System.ArgumentException(); } BigDecimal initialGuess = GetInitialApproximation(n); BigDecimal lastGuess = ZERO; BigDecimal guess = new BigDecimal(initialGuess.ToString()); int iterations = 0; bool more = true; while (more) { lastGuess = guess; guess = n.divide(guess, scale, BigDecimal.ROUND_HALF_UP); guess = guess.add(lastGuess); guess = guess.divide(TWO, scale, BigDecimal.ROUND_HALF_UP); error = n.subtract(guess.multiply(guess)); if (++iterations >= maxIterations) { more = false; } else if (lastGuess.Equals(guess)) { more = error.abs().CompareTo(ONE) >= 0; } } return(guess); }
public static void CheckUpperBound(BigDecimal val) { if (val.CompareTo(MaxNativeValue) == 1) { throw GetOutOfBoundsException(val, "bigger", MaxNativeValue); } }
/// <summary>Returns a list of BigDecimals one element longer than the list of input splits. /// </summary> /// <remarks> /// Returns a list of BigDecimals one element longer than the list of input splits. /// This represents the boundaries between input splits. /// All splits are open on the top end, except the last one. /// So the list [0, 5, 8, 12, 18] would represent splits capturing the intervals: /// [0, 5) /// [5, 8) /// [8, 12) /// [12, 18] note the closed interval for the last split. /// </remarks> /// <exception cref="Java.Sql.SQLException"/> internal virtual IList <BigDecimal> Split(BigDecimal numSplits, BigDecimal minVal, BigDecimal maxVal) { IList <BigDecimal> splits = new AList <BigDecimal>(); // Use numSplits as a hint. May need an extra task if the size doesn't // divide cleanly. BigDecimal splitSize = TryDivide(maxVal.Subtract(minVal), (numSplits)); if (splitSize.CompareTo(MinIncrement) < 0) { splitSize = MinIncrement; Log.Warn("Set BigDecimal splitSize to MIN_INCREMENT"); } BigDecimal curVal = minVal; while (curVal.CompareTo(maxVal) <= 0) { splits.AddItem(curVal); curVal = curVal.Add(splitSize); } if (splits[splits.Count - 1].CompareTo(maxVal) != 0 || splits.Count == 1) { // We didn't end on the maxVal. Add that to the end of the list. splits.AddItem(maxVal); } return(splits); }
public void CompareToTest() { var v1 = new BigDecimal(100.001m); var v2 = new BigDecimal(100.001m); Assert.IsTrue(v1.CompareTo(v2) == 0); }
public void Compare_MultipleValues_Pass() { var num1 = new BigDecimal(20); var num2 = new BigDecimal(30); var actual = num1.CompareTo(num2); var expected = -1; Assert.AreEqual(expected, actual); actual = num1.CompareTo(num1); expected = 0; Assert.AreEqual(expected, actual); actual = num2.CompareTo(num1); expected = 1; Assert.AreEqual(expected, actual); }
public void CompareToBigDecimal() { BigDecimal comp1 = BigDecimal.Parse("1.00"); BigDecimal comp2 = new BigDecimal(1.000000D); Assert.IsTrue(comp1.CompareTo(comp2) == 0, "1.00 and 1.000000 should be equal"); BigDecimal comp3 = BigDecimal.Parse("1.02"); Assert.IsTrue(comp3.CompareTo(comp1) == 1, "1.02 should be bigger than 1.00"); BigDecimal comp4 = new BigDecimal(0.98D); Assert.IsTrue(comp4.CompareTo(comp1) == -1, "0.98 should be less than 1.00"); }
public String Format(BigDecimal b, int maxLength, int maxNumberOfIntegers, int maxNumberOfDecimals, bool padFractions) { String basePattern = "0." + StringUtils.Repeat(padFractions ? "0" : "#", maxNumberOfDecimals); String text = String.Format("{0:" + basePattern + "}", (decimal)b); // the above takes care of the decimals having too many digits; now to handle digits to left of decimal. // this code preserves a negative sign to match what the java code does (this is possibly not ideal) int decimalLocation = text.IndexOf("."); if (decimalLocation > maxNumberOfIntegers) { return((b.CompareTo(BigDecimal.ZERO) < 0 ? "-" : "") + text.Substring(decimalLocation - maxNumberOfIntegers)); } else if (decimalLocation == -1 && text.Length > maxNumberOfIntegers) { return((b.CompareTo(BigDecimal.ZERO) < 0 ? "-" : "") + text.Substring(text.Length - maxNumberOfIntegers)); } else { return(text); } }
public BigDecimal calDens(BigDecimal radius) { BigDecimal vol = BigDecimal.Parse("0.0"); BigDecimal num = BigDecimal.Parse("1.33333333333"); BigDecimal pi = BigDecimal.Parse(Math.PI.ToString()); BigDecimal mass = BigInteger.Parse("1990000000000000000000000000000"); BigDecimal dens = BigDecimal.Parse("0.0"); num = num.Multiply(pi); vol = radius.Pow(3); vol = num.Multiply(vol); dens = mass / (vol); //while (mass.compareTo(vol.toBigInteger()) < 0) while (mass.CompareTo(((BigInteger)vol)) < 0) { if (type == ("Average_Star")) { mass = range(Average_Starmax, Average_Starmin); } if (type == ("Massive_Star")) { mass = range(Massive_Starmax, Massive_Starmin); } if (type == ("White_Dwarf")) { mass = range(White_Dwarfmax, White_Dwarfmin); } if (type == ("Neutron_Star")) { mass = range(Neutron_Starmax, Neutron_Starmin); } if (type == ("Black_hole")) { mass = range(Black_holemax, Black_holemin); } else { break; } } dens = mass / (vol); density = dens; //if(density.compareTo(BigDecimal.Parse("1")) < 0 ){ // Console.WriteLine("its 0"); // System.exit(0); //} return(dens); }
public Number Divide(Number number) { if (numberState == 0) { if (number.numberState == 0) { BigDecimal divBy = number.bigDecimal; if (divBy.CompareTo(BdZero) != 0) { return(new Number(NumberState.None, bigDecimal.Divide(divBy, 10, RoundingMode.HalfUp))); } } } // Return NaN if we can't divide return(new Number(NumberState.NotANumber, null)); }
public static SqlNumber Remainder(SqlNumber a, SqlNumber b) { if (SqlNumber.IsNumber(a)) { if (SqlNumber.IsNumber(b)) { BigDecimal divBy = b.innerValue; if (divBy.CompareTo(BigDecimal.Zero) != 0) { var remainder = BigMath.Remainder(a.innerValue, divBy); return(new SqlNumber(SqlNumber.NumericState.None, remainder)); } } } return(SqlNumber.NaN); }
public Number Modulus(Number number) { if (numberState == 0) { if (number.numberState == 0) { BigDecimal divBy = number.bigDecimal; if (divBy.CompareTo(BdZero) != 0) { BigDecimal remainder = bigDecimal.Remainder(divBy); return(new Number(NumberState.None, remainder)); } } } return(new Number(NumberState.NotANumber, null)); }
private static BigDecimal SqrtNewtonRaphson(BigDecimal c, BigDecimal xn, BigDecimal precision) { BigDecimal fx = xn.Pow(2).Add(c.Negate()); BigDecimal fpx = xn.Multiply(new BigDecimal(2)); BigDecimal xn1 = fx.Divide(fpx, 2 * SqrtDig.ToInt32(), RoundingMode.HalfDown); xn1 = xn.Add(xn1.Negate()); //---- BigDecimal currentSquare = xn1.Pow(2); BigDecimal currentPrecision = currentSquare.Subtract(c); currentPrecision = currentPrecision.Abs(); if (currentPrecision.CompareTo(precision) <= -1) { return(xn1); } return(SqrtNewtonRaphson(c, xn1, precision)); }
public static SqlNumber Divide(SqlNumber a, SqlNumber b, int precision) { if (SqlNumber.IsNumber(a)) { if (SqlNumber.IsNumber(b)) { BigDecimal divBy = b.innerValue; if (divBy.CompareTo(BigDecimal.Zero) != 0) { var context = new MathContext(precision); var result = BigMath.Divide(a.innerValue, divBy, context); return(new SqlNumber(SqlNumber.NumericState.None, result)); } throw new DivideByZeroException(); } } // Return NaN if we can't divide return(SqlNumber.NaN); }
public SqlNumber Modulo(SqlNumber value) { if (State == NumericState.None) { if (value.State == NumericState.None) { if (IsNull || value.IsNull) { return(Null); } BigDecimal divBy = value.innerValue; if (divBy.CompareTo(BigDecimal.Zero) != 0) { BigDecimal remainder = innerValue.Remainder(divBy); return(new SqlNumber(NumericState.None, remainder)); } } } return(new SqlNumber(NumericState.NotANumber, null)); }
public SqlNumber Divide(SqlNumber value) { if (State == NumericState.None) { if (value.State == NumericState.None) { if (IsNull || value.IsNull) { return(Null); } BigDecimal divBy = value.innerValue; if (divBy.CompareTo(BigDecimal.Zero) != 0) { return(new SqlNumber(NumericState.None, innerValue.Divide(divBy, 10, RoundingMode.HalfUp))); } } } // Return NaN if we can't divide return(new SqlNumber(NumericState.NotANumber, null)); }
public static BigDecimal Exp(BigDecimal x) { /* To calculate the value if x is negative, use exp(-x) = 1/exp(x) */ if (x.CompareTo(BigDecimal.Zero) < 0) { BigDecimal invx = Exp(x.Negate()); /* Relative error in inverse of invx is the same as the relative errror in invx. * This is used to define the precision of the result. */ var mc = new MathContext(invx.Precision); return BigDecimal.One.Divide(invx, mc); } if (x.CompareTo(BigDecimal.Zero) == 0) { /* recover the valid number of digits from x.ulp(), if x hits the * zero. The x.precision() is 1 then, and does not provide this information. */ return ScalePrecision(BigDecimal.One, -(int) (System.Math.Log10(x.Ulp().ToDouble()))); } /* Push the number in the Taylor expansion down to a small * value where TAYLOR_NTERM terms will do. If x<1, the n-th term is of the order * x^n/n!, and equal to both the absolute and relative error of the result * since the result is close to 1. The x.ulp() sets the relative and absolute error * of the result, as estimated from the first Taylor term. * We want x^TAYLOR_NTERM/TAYLOR_NTERM! < x.ulp, which is guaranteed if * x^TAYLOR_NTERM < TAYLOR_NTERM*(TAYLOR_NTERM-1)*...*x.ulp. */ double xDbl = x.ToDouble(); double xUlpDbl = x.Ulp().ToDouble(); if (System.Math.Pow(xDbl, TaylorNterm) < TaylorNterm*(TaylorNterm - 1.0)*(TaylorNterm - 2.0)*xUlpDbl) { /* Add TAYLOR_NTERM terms of the Taylor expansion (Euler's sum formula) */ BigDecimal resul = BigDecimal.One; /* x^i */ BigDecimal xpowi = BigDecimal.One; /* i factorial */ BigInteger ifac = BigInteger.One; /* TAYLOR_NTERM terms to be added means we move x.ulp() to the right * for each power of 10 in TAYLOR_NTERM, so the addition won't add noise beyond * what's already in x. */ var mcTay = new MathContext(ErrorToPrecision(1d, xUlpDbl/TaylorNterm)); for (int i = 1; i <= TaylorNterm; i++) { ifac = ifac.Multiply(BigInteger.ValueOf(i)); xpowi = xpowi.Multiply(x); BigDecimal c = xpowi.Divide(new BigDecimal(ifac), mcTay); resul = resul.Add(c); if (System.Math.Abs(xpowi.ToDouble()) < i && System.Math.Abs(c.ToDouble()) < 0.5*xUlpDbl) break; } /* exp(x+deltax) = exp(x)(1+deltax) if deltax is <<1. So the relative error * in the result equals the absolute error in the argument. */ var mc = new MathContext(ErrorToPrecision(xUlpDbl/2d)); return resul.Round(mc); } else { /* Compute exp(x) = (exp(0.1*x))^10. Division by 10 does not lead * to loss of accuracy. */ var exSc = (int) (1.0 - System.Math.Log10(TaylorNterm*(TaylorNterm - 1.0)*(TaylorNterm - 2.0)*xUlpDbl /System.Math.Pow(xDbl, TaylorNterm))/(TaylorNterm - 1.0)); BigDecimal xby10 = x.ScaleByPowerOfTen(-exSc); BigDecimal expxby10 = Exp(xby10); /* Final powering by 10 means that the relative error of the result * is 10 times the relative error of the base (First order binomial expansion). * This looses one digit. */ var mc = new MathContext(expxby10.Precision - exSc); /* Rescaling the powers of 10 is done in chunks of a maximum of 8 to avoid an invalid operation * response by the BigDecimal.pow library or integer overflow. */ while (exSc > 0) { int exsub = System.Math.Min(8, exSc); exSc -= exsub; var mctmp = new MathContext(expxby10.Precision - exsub + 2); int pex = 1; while (exsub-- > 0) pex *= 10; expxby10 = expxby10.Pow(pex, mctmp); } return expxby10.Round(mc); } }
public static BigDecimal Cot(BigDecimal x) { if (x.CompareTo(BigDecimal.Zero) == 0) { throw new ArithmeticException("Cannot take cot of zero " + x); } if (x.CompareTo(BigDecimal.Zero) < 0) { return Cot(x.Negate()).Negate(); } /* reduce modulo pi */ BigDecimal res = ModPi(x); /* absolute error in the result is err(x)/sin^2(x) to lowest order */ double xDbl = res.ToDouble(); double xUlpDbl = x.Ulp().ToDouble()/2d; double eps = xUlpDbl/2d/System.Math.Pow(System.Math.Sin(xDbl), 2d); BigDecimal xhighpr = ScalePrecision(res, 2); BigDecimal xhighprSq = MultiplyRound(xhighpr, xhighpr); var mc = new MathContext(ErrorToPrecision(xhighpr.ToDouble(), eps)); BigDecimal resul = BigDecimal.One.Divide(xhighpr, mc); /* x^(2i-1) */ BigDecimal xpowi = xhighpr; var b = new Bernoulli(); /* 2^(2i) */ var fourn = BigInteger.Parse("4"); /* (2i)! */ BigInteger fac = BigInteger.One; for (int i = 1;; i++) { Rational f = b[2*i]; fac = fac.Multiply(BigInteger.ValueOf((2*i))).Multiply(BigInteger.ValueOf((2*i - 1))); f = f.Multiply(fourn).Divide(fac); BigDecimal c = MultiplyRound(xpowi, f); if (i%2 == 0) resul = resul.Add(c); else resul = resul.Subtract(c); if (System.Math.Abs(c.ToDouble()) < 0.1*eps) break; fourn = fourn.ShiftLeft(2); xpowi = MultiplyRound(xpowi, xhighprSq); } mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps)); return resul.Round(mc); }
public static BigDecimal Cos(BigDecimal x) { if (x.CompareTo(BigDecimal.Zero) < 0) return Cos(x.Negate()); if (x.CompareTo(BigDecimal.Zero) == 0) return BigDecimal.One; /* reduce modulo 2pi */ BigDecimal res = Mod2Pi(x); double errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble()); var mc = new MathContext(2 + ErrorToPrecision(3.14159, errpi)); BigDecimal p = PiRound(mc); mc = new MathContext(x.Precision); if (res.CompareTo(p) > 0) { /* pi<x<=2pi: cos(x)= - cos(x-pi) */ return Cos(SubtractRound(res, p)).Negate(); } if (res.Multiply(BigDecimal.ValueOf(2)).CompareTo(p) > 0) { /* pi/2<x<=pi: cos(x)= -cos(pi-x) */ return Cos(SubtractRound(p, res)).Negate(); } /* for the range 0<=x<Pi/2 one could use cos(2x)= 1-2*sin^2(x) * to split this further, or use the cos up to pi/4 and the sine higher up. throw new ProviderException("Not implemented: cosine ") ; */ if (res.Multiply(BigDecimal.ValueOf(4)).CompareTo(p) > 0) { /* x>pi/4: cos(x) = sin(pi/2-x) */ return Sin(SubtractRound(p.Divide(BigDecimal.ValueOf(2)), res)); } /* Simple Taylor expansion, sum_{i=0..infinity} (-1)^(..)res^(2i)/(2i)! */ BigDecimal resul = BigDecimal.One; /* x^i */ BigDecimal xpowi = BigDecimal.One; /* 2i factorial */ BigInteger ifac = BigInteger.One; /* The absolute error in the result is the error in x^2/2 which is x times the error in x. */ double xUlpDbl = 0.5*res.Ulp().ToDouble()*res.ToDouble(); /* The error in the result is set by the error in x^2/2 itself, xUlpDbl. * We need at most k terms to push x^(2k+1)/(2k+1)! below this value. * x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl); */ int k = (int) (System.Math.Log(xUlpDbl)/System.Math.Log(res.ToDouble()))/2; var mcTay = new MathContext(ErrorToPrecision(1d, xUlpDbl/k)); for (int i = 1;; i++) { /* TBD: at which precision will 2*i-1 or 2*i overflow? */ ifac = ifac.Multiply(BigInteger.ValueOf((2*i - 1))); ifac = ifac.Multiply(BigInteger.ValueOf((2*i))); xpowi = xpowi.Multiply(res).Multiply(res).Negate(); BigDecimal corr = xpowi.Divide(new BigDecimal(ifac), mcTay); resul = resul.Add(corr); if (corr.Abs().ToDouble() < 0.5*xUlpDbl) break; } /* The error in the result is governed by the error in x itself. */ mc = new MathContext(ErrorToPrecision(resul.ToDouble(), xUlpDbl)); return resul.Round(mc); }
public static BigDecimal Cbrt(BigDecimal x) { if (x.CompareTo(BigDecimal.Zero) < 0) return Root(3, x.Negate()).Negate(); return Root(3, x); }
public static BigDecimal Asin(BigDecimal x) { if (x.CompareTo(BigDecimal.One) > 0 || x.CompareTo(BigDecimal.One.Negate()) < 0) { throw new ArithmeticException("Out of range argument " + x + " of asin"); } if (x.CompareTo(BigDecimal.Zero) == 0) return BigDecimal.Zero; if (x.CompareTo(BigDecimal.One) == 0) { /* arcsin(1) = pi/2 */ double errpi = System.Math.Sqrt(x.Ulp().ToDouble()); var mc = new MathContext(ErrorToPrecision(3.14159, errpi)); return PiRound(mc).Divide(new BigDecimal(2)); } if (x.CompareTo(BigDecimal.Zero) < 0) { return Asin(x.Negate()).Negate(); } if (x.ToDouble() > 0.7) { BigDecimal xCompl = BigDecimal.One.Subtract(x); double xDbl = x.ToDouble(); double xUlpDbl = x.Ulp().ToDouble()/2d; double eps = xUlpDbl/2d/System.Math.Sqrt(1d - System.Math.Pow(xDbl, 2d)); BigDecimal xhighpr = ScalePrecision(xCompl, 3); BigDecimal xhighprV = DivideRound(xhighpr, 4); BigDecimal resul = BigDecimal.One; /* x^(2i+1) */ BigDecimal xpowi = BigDecimal.One; /* i factorial */ BigInteger ifacN = BigInteger.One; BigInteger ifacD = BigInteger.One; for (int i = 1;; i++) { ifacN = ifacN.Multiply(BigInteger.ValueOf((2*i - 1))); ifacD = ifacD.Multiply(BigInteger.ValueOf(i)); if (i == 1) xpowi = xhighprV; else xpowi = MultiplyRound(xpowi, xhighprV); BigDecimal c = DivideRound(MultiplyRound(xpowi, ifacN), ifacD.Multiply(BigInteger.ValueOf((2*i + 1)))); resul = resul.Add(c); /* series started 1+x/12+... which yields an estimate of the sum's error */ if (System.Math.Abs(c.ToDouble()) < xUlpDbl/120d) break; } /* sqrt(2*z)*(1+...) */ xpowi = Sqrt(xhighpr.Multiply(new BigDecimal(2))); resul = MultiplyRound(xpowi, resul); var mc = new MathContext(resul.Precision); BigDecimal pihalf = PiRound(mc).Divide(new BigDecimal(2)); mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps)); return pihalf.Subtract(resul, mc); } else { /* absolute error in the result is err(x)/sqrt(1-x^2) to lowest order */ double xDbl = x.ToDouble(); double xUlpDbl = x.Ulp().ToDouble()/2d; double eps = xUlpDbl/2d/System.Math.Sqrt(1d - System.Math.Pow(xDbl, 2d)); BigDecimal xhighpr = ScalePrecision(x, 2); BigDecimal xhighprSq = MultiplyRound(xhighpr, xhighpr); BigDecimal resul = xhighpr.Plus(); /* x^(2i+1) */ BigDecimal xpowi = xhighpr; /* i factorial */ BigInteger ifacN = BigInteger.One; BigInteger ifacD = BigInteger.One; for (int i = 1;; i++) { ifacN = ifacN.Multiply(BigInteger.ValueOf((2*i - 1))); ifacD = ifacD.Multiply(BigInteger.ValueOf((2*i))); xpowi = MultiplyRound(xpowi, xhighprSq); BigDecimal c = DivideRound(MultiplyRound(xpowi, ifacN), ifacD.Multiply(BigInteger.ValueOf((2*i + 1)))); resul = resul.Add(c); if (System.Math.Abs(c.ToDouble()) < 0.1*eps) break; } var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps)); return resul.Round(mc); } }
public static BigDecimal Tan(BigDecimal x) { if (x.CompareTo(BigDecimal.Zero) == 0) return BigDecimal.Zero; if (x.CompareTo(BigDecimal.Zero) < 0) { return Tan(x.Negate()).Negate(); } /* reduce modulo pi */ BigDecimal res = ModPi(x); /* absolute error in the result is err(x)/cos^2(x) to lowest order */ double xDbl = res.ToDouble(); double xUlpDbl = x.Ulp().ToDouble()/2d; double eps = xUlpDbl/2d/System.Math.Pow(System.Math.Cos(xDbl), 2d); if (xDbl > 0.8) { /* tan(x) = 1/cot(x) */ BigDecimal co = Cot(x); var mc = new MathContext(ErrorToPrecision(1d/co.ToDouble(), eps)); return BigDecimal.One.Divide(co, mc); } else { BigDecimal xhighpr = ScalePrecision(res, 2); BigDecimal xhighprSq = MultiplyRound(xhighpr, xhighpr); BigDecimal resul = xhighpr.Plus(); /* x^(2i+1) */ BigDecimal xpowi = xhighpr; var b = new Bernoulli(); /* 2^(2i) */ BigInteger fourn = BigInteger.ValueOf(4); /* (2i)! */ BigInteger fac = BigInteger.ValueOf(2); for (int i = 2;; i++) { Rational f = b[2*i].Abs(); fourn = fourn.ShiftLeft(2); fac = fac.Multiply(BigInteger.ValueOf((2*i))).Multiply(BigInteger.ValueOf((2*i - 1))); f = f.Multiply(fourn).Multiply(fourn.Subtract(BigInteger.One)).Divide(fac); xpowi = MultiplyRound(xpowi, xhighprSq); BigDecimal c = MultiplyRound(xpowi, f); resul = resul.Add(c); if (System.Math.Abs(c.ToDouble()) < 0.1*eps) break; } var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps)); return resul.Round(mc); } }
public static BigDecimal Sqrt(BigDecimal x, MathContext mc) { if (x.CompareTo(BigDecimal.Zero) < 0) throw new ArithmeticException("negative argument " + x + " of square root"); if (x.Abs().Subtract(new BigDecimal(System.Math.Pow(10d, -mc.Precision))).CompareTo(BigDecimal.Zero) < 0) return ScalePrecision(BigDecimal.Zero, mc); /* start the computation from a double precision estimate */ var s = new BigDecimal(System.Math.Sqrt(x.ToDouble()), mc); BigDecimal half = BigDecimal.ValueOf(2); /* increase the local accuracy by 2 digits */ var locmc = new MathContext(mc.Precision + 2, mc.RoundingMode); /* relative accuracy requested is 10^(-precision) */ double eps = System.Math.Pow(10.0, -mc.Precision); while (true) { /* s = s -(s/2-x/2s); test correction s-x/s for being * smaller than the precision requested. The relative correction is 1-x/s^2, * (actually half of this, which we use for a little bit of additional protection). */ if (System.Math.Abs(BigDecimal.One.Subtract(x.Divide(s.Pow(2, locmc), locmc)).ToDouble()) < eps) break; s = s.Add(x.Divide(s, locmc)).Divide(half, locmc); } return s; }
public override void Init(IokeObject obj) { Runtime runtime = obj.runtime; obj.Kind = "Number Decimal"; runtime.Decimal = obj; obj.RegisterMethod(runtime.NewNativeMethod("returns true if the left hand side decimal is equal to the right hand side decimal.", new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(runtime.Decimal) .WithRequiredPositional("other") .Arguments, (method, on, args, keywords, context, message) => { Decimal d = (Decimal)IokeObject.dataOf(on); object other = args[0]; return(((other is IokeObject) && (IokeObject.dataOf(other) is Decimal) && ((on == context.runtime.Decimal && other == on) || d.value.Equals(((Decimal)IokeObject.dataOf(other)).value))) ? context.runtime.True : context.runtime.False); }))); obj.RegisterMethod(runtime.NewNativeMethod("Returns a text representation of the object", new TypeCheckingNativeMethod.WithNoArguments("asText", obj, (method, on, args, keywords, context, message) => { return(runtime.NewText(on.ToString())); }))); obj.RegisterMethod(runtime.NewNativeMethod("returns the square root of the receiver. this should return the same result as calling ** with 0.5", new TypeCheckingNativeMethod.WithNoArguments("sqrt", obj, (method, on, args, keywords, context, message) => { BigDecimal value = ((Decimal)IokeObject.dataOf(on)).value; if (value.CompareTo(BigDecimal.ZERO) < 1) { IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition, message, context, "Error", "Arithmetic"), context).Mimic(message, context); condition.SetCell("message", message); condition.SetCell("context", context); condition.SetCell("receiver", on); context.runtime.ErrorCondition(condition); } return(runtime.NewDecimal(new BigSquareRoot().Get(value))); }))); obj.RegisterMethod(obj.runtime.NewNativeMethod("Returns a text inspection of the object", new TypeCheckingNativeMethod.WithNoArguments("inspect", obj, (method, on, args, keywords, context, message) => { return(method.runtime.NewText(Decimal.GetInspect(on))); }))); obj.RegisterMethod(obj.runtime.NewNativeMethod("Returns a brief text inspection of the object", new TypeCheckingNativeMethod.WithNoArguments("notice", obj, (method, on, args, keywords, context, message) => { return(method.runtime.NewText(Decimal.GetInspect(on))); }))); obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a hash for the decimal number", new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => { outer.ArgumentsDefinition.CheckArgumentCount(context, message, on); return(context.runtime.NewNumber(Decimal.GetValue(on).GetHashCode())); }))); obj.RegisterMethod(runtime.NewNativeMethod("compares this number against the argument, true if this number is the same, otherwise false", new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("other") .Arguments, (method, on, args, keywords, context, message) => { object arg = args[0]; if (IokeObject.dataOf(arg) is Number) { return((Decimal.GetValue(on).CompareTo(Number.GetValue(arg).AsBigDecimal()) == 0) ? context.runtime.True : context.runtime.False); } else if (IokeObject.dataOf(arg) is Decimal) { return((Decimal.GetValue(on).CompareTo(Decimal.GetValue(arg)) == 0) ? context.runtime.True : context.runtime.False); } else { return(context.runtime.False); } }))); obj.RegisterMethod(runtime.NewNativeMethod("compares this number against the argument, returning -1, 0 or 1 based on which one is larger. if the argument is a rational, it will be converted into a form suitable for comparing against a decimal, and then compared. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that doesn't work it returns nil.", new TypeCheckingNativeMethod("<=>", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("other") .Arguments, (method, on, args, keywords, context, message) => { object arg = args[0]; IokeData data = IokeObject.dataOf(arg); if (data is Number) { return(context.runtime.NewNumber(Decimal.GetValue(on).CompareTo(Number.GetValue(arg).AsBigDecimal()))); } else { if (!(data is Decimal)) { arg = IokeObject.ConvertToDecimal(arg, message, context, false); if (!(IokeObject.dataOf(arg) is Decimal)) { // Can't compare, so bail out return(context.runtime.nil); } } if (on == context.runtime.Decimal || arg == context.runtime.Decimal) { if (arg == on) { return(context.runtime.NewNumber(0)); } return(context.runtime.nil); } return(context.runtime.NewNumber(Decimal.GetValue(on).CompareTo(Decimal.GetValue(arg)))); } }))); obj.RegisterMethod(runtime.NewNativeMethod("returns the difference between this number and the argument. if the argument is a rational, it will be converted into a form suitable for subtracting against a decimal, and then subtracted. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that fails it signals a condition.", new TypeCheckingNativeMethod("-", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("subtrahend") .Arguments, (method, on, args, keywords, context, message) => { object arg = args[0]; IokeData data = IokeObject.dataOf(arg); if (data is Number) { return(context.runtime.NewDecimal(Decimal.GetValue(on).subtract(Number.GetValue(arg).AsBigDecimal()))); } else { if (!(data is Decimal)) { arg = IokeObject.ConvertToDecimal(arg, message, context, true); } return(context.runtime.NewDecimal(Decimal.GetValue(on).subtract(Decimal.GetValue(arg)))); } }))); obj.RegisterMethod(runtime.NewNativeMethod("returns the sum of this number and the argument. if the argument is a rational, it will be converted into a form suitable for addition against a decimal, and then added. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that fails it signals a condition.", new TypeCheckingNativeMethod("+", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("addend") .Arguments, (method, on, args, keywords, context, message) => { object arg = args[0]; IokeData data = IokeObject.dataOf(arg); if (data is Number) { return(context.runtime.NewDecimal(Decimal.GetValue(on).add(Number.GetValue(arg).AsBigDecimal()))); } else { if (!(data is Decimal)) { arg = IokeObject.ConvertToDecimal(arg, message, context, true); } return(context.runtime.NewDecimal(Decimal.GetValue(on).add(Decimal.GetValue(arg)))); } }))); obj.RegisterMethod(runtime.NewNativeMethod("returns the product of this number and the argument. if the argument is a rational, the receiver will be converted into a form suitable for multiplying against a decimal, and then multiplied. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that fails it signals a condition.", new TypeCheckingNativeMethod("*", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("multiplier") .Arguments, (method, on, args, keywords, context, message) => { object arg = args[0]; IokeData data = IokeObject.dataOf(arg); if (data is Number) { return(context.runtime.NewDecimal(Decimal.GetValue(on).multiply(Number.GetValue(arg).AsBigDecimal()))); } else { if (!(data is Decimal)) { arg = IokeObject.ConvertToDecimal(arg, message, context, true); } return(context.runtime.NewDecimal(Decimal.GetValue(on).multiply(Decimal.GetValue(arg)))); } }))); obj.RegisterMethod(runtime.NewNativeMethod("returns this number to the power of the argument (which has to be an integer)", new TypeCheckingNativeMethod("**", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("exponent") .Arguments, (method, on, args, keywords, context, message) => { object arg = args[0]; IokeData data = IokeObject.dataOf(arg); if (!(data is Number)) { arg = IokeObject.ConvertToRational(arg, message, context, true); } return(context.runtime.NewDecimal(Decimal.GetValue(on).pow(Number.IntValue(arg).intValue()))); }))); obj.RegisterMethod(runtime.NewNativeMethod("returns the quotient of this number and the argument.", new TypeCheckingNativeMethod("/", TypeCheckingArgumentsDefinition.builder() .ReceiverMustMimic(obj) .WithRequiredPositional("divisor") .Arguments, (method, on, args, keywords, context, message) => { object arg = args[0]; IokeData data = IokeObject.dataOf(arg); if (data is Number) { return(context.runtime.NewDecimal(Decimal.GetValue(on).divide(Number.GetValue(arg).AsBigDecimal()))); } else { if (!(data is Decimal)) { arg = IokeObject.ConvertToDecimal(arg, message, context, true); } while (Decimal.GetValue(arg).CompareTo(BigDecimal.ZERO) == 0) { IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition, message, context, "Error", "Arithmetic", "DivisionByZero"), context).Mimic(message, context); condition.SetCell("message", message); condition.SetCell("context", context); condition.SetCell("receiver", on); object[] newCell = new object[] { arg }; context.runtime.WithRestartReturningArguments(() => { context.runtime.ErrorCondition(condition); }, context, new IokeObject.UseValue("newValue", newCell)); arg = newCell[0]; } BigDecimal result = null; try { result = Decimal.GetValue(on).divide(Decimal.GetValue(arg), BigDecimal.ROUND_UNNECESSARY); } catch (System.ArithmeticException) { result = Decimal.GetValue(on).divide(Decimal.GetValue(arg), MathContext.DECIMAL128); } return(context.runtime.NewDecimal(result)); } }))); }
public int CompareTo(Number number) { if (Equals(this, number)) { return(0); } // If this is a non-infinity number if (numberState == 0) { // If both values can be represented by a long value if (CanBeLong && number.CanBeLong) { // Perform a long comparison check, if (longRepresentation > number.longRepresentation) { return(1); } if (longRepresentation < number.longRepresentation) { return(-1); } return(0); } // And the compared number is non-infinity then use the BigDecimal // compareTo method. if (number.numberState == 0) { return(bigDecimal.CompareTo(number.bigDecimal)); } // Comparing a regular number with a NaN number. // If positive infinity or if NaN if (number.numberState == NumberState.PositiveInfinity || number.numberState == NumberState.NotANumber) { return(-1); } // If negative infinity if (number.numberState == NumberState.NegativeInfinity) { return(1); } throw new ApplicationException("Unknown number state."); } // This number is a NaN number. // Are we comparing with a regular number? if (number.numberState == 0) { // Yes, negative infinity if (numberState == NumberState.NegativeInfinity) { return(-1); } // positive infinity or NaN if (numberState == NumberState.PositiveInfinity || numberState == NumberState.NotANumber) { return(1); } throw new ApplicationException("Unknown number state."); } // Comparing NaN number with a NaN number. // This compares -Inf less than Inf and NaN and NaN greater than // Inf and -Inf. -Inf < Inf < NaN return(numberState - number.numberState); }
///*** // * Creates {@code H} of size {@code m x m} as described in [1] (see above). // * // * @param d statistic // * @return H matrix // * @throws NumberIsTooLargeException if fractional part is greater than 1 // * @throws FractionConversionException if algorithm fails to convert // * {@code h} to a {@link org.apache.commons.math3.fraction.BigFraction} in // * expressing {@code d} as {@code (k - h) / m} for integer {@code k, m} and // * {@code 0 <= h < 1}. // */ private BigDecimal[,] createH(double d) { int k = (int)Math.Ceiling(n * d); int m = 2 * k - 1; double hDouble = k - n * d; if (hDouble >= 1) { throw new Exception("Value to large: " + hDouble); } BigDecimal h = hDouble; BigDecimal[,] Hdata = new BigDecimal[m, m]; ///* // * Start by filling everything with either 0 or 1. // */ for (int i = 0; i < m; ++i) { for (int j = 0; j < m; ++j) { if (i - j + 1 < 0) { Hdata[i, j] = 0.0; } else { Hdata[i, j] = 1.0; } } } ///* // * Setting up power-array to avoid calculating the same value twice: // * hPowers[0] = h^1 ... hPowers[m-1] = h^m // */ BigDecimal[] hPowers = new BigDecimal[m]; hPowers[0] = h; for (int i = 1; i < m; ++i) { hPowers[i] = h * (hPowers[i - 1]); } ///* // * First column and last row has special values (each other reversed). // */ for (int i = 0; i < m; ++i) { Hdata[i, 0] = Hdata[i, 0] - (hPowers[i]); Hdata[m - 1, i] = Hdata[m - 1, i] - (hPowers[m - i - 1]); } ///* // * [1] states: "For 1/2 < h < 1 the bottom left element of the matrix // * should be (1 - 2*h^m + (2h - 1)^m )/m!" Since 0 <= h < 1, then if h > // * 1/2 is sufficient to check: // */ if (h.CompareTo(0.5) == 1) { Hdata[m - 1, 0] = Hdata[m - 1, 0] + ToolsMathBigDecimal.Pow((h * 2) - 1, m); } ///* // * Aside from the first column and last row, the (i, j)-th element is // * 1/(i - j + 1)! if i - j + 1 >= 0, else 0. 1's and 0's are already // * put, so only division with (i - j + 1)! is needed in the elements // * that have 1's. There is no need to calculate (i - j + 1)! and then // * divide - small steps avoid overflows. // * // * Note that i - j + 1 > 0 <=> i + 1 > j instead of j'ing all the way to // * m. Also note that it is started at g = 2 because dividing by 1 isn't // * really necessary. // */ for (int i = 0; i < m; ++i) { for (int j = 0; j < i + 1; ++j) { if (i - j + 1 > 0) { for (int g = 2; g <= i - j + 1; ++g) { Hdata[i, j] = Hdata[i, j] / g; } } } } return(Hdata); }
public static BigDecimal Log(BigDecimal x) { /* the value is undefined if x is negative. */ if (x.CompareTo(BigDecimal.Zero) < 0) throw new ArithmeticException("Cannot take log of negative " + x); if (x.CompareTo(BigDecimal.One) == 0) { /* log 1. = 0. */ return ScalePrecision(BigDecimal.Zero, x.Precision - 1); } if (System.Math.Abs(x.ToDouble() - 1.0) <= 0.3) { /* The standard Taylor series around x=1, z=0, z=x-1. Abramowitz-Stegun 4.124. * The absolute error is err(z)/(1+z) = err(x)/x. */ BigDecimal z = ScalePrecision(x.Subtract(BigDecimal.One), 2); BigDecimal zpown = z; double eps = 0.5*x.Ulp().ToDouble()/System.Math.Abs(x.ToDouble()); BigDecimal resul = z; for (int k = 2;; k++) { zpown = MultiplyRound(zpown, z); BigDecimal c = DivideRound(zpown, k); if (k%2 == 0) resul = resul.Subtract(c); else resul = resul.Add(c); if (System.Math.Abs(c.ToDouble()) < eps) break; } var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), eps)); return resul.Round(mc); } else { double xDbl = x.ToDouble(); double xUlpDbl = x.Ulp().ToDouble(); /* Map log(x) = log root[r](x)^r = r*log( root[r](x)) with the aim * to move roor[r](x) near to 1.2 (that is, below the 0.3 appearing above), where log(1.2) is roughly 0.2. */ var r = (int) (System.Math.Log(xDbl)/0.2); /* Since the actual requirement is a function of the value 0.3 appearing above, * we avoid the hypothetical case of endless recurrence by ensuring that r >= 2. */ r = System.Math.Max(2, r); /* Compute r-th root with 2 additional digits of precision */ BigDecimal xhighpr = ScalePrecision(x, 2); BigDecimal resul = Root(r, xhighpr); resul = Log(resul).Multiply(new BigDecimal(r)); /* error propagation: log(x+errx) = log(x)+errx/x, so the absolute error * in the result equals the relative error in the input, xUlpDbl/xDbl . */ var mc = new MathContext(ErrorToPrecision(resul.ToDouble(), xUlpDbl/xDbl)); return resul.Round(mc); } }
public static BigDecimal Sin(BigDecimal x) { if (x.CompareTo(BigDecimal.Zero) < 0) return Sin(x.Negate()).Negate(); if (x.CompareTo(BigDecimal.Zero) == 0) return BigDecimal.Zero; /* reduce modulo 2pi */ BigDecimal res = Mod2Pi(x); double errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble()); var mc = new MathContext(2 + ErrorToPrecision(3.14159, errpi)); BigDecimal p = PiRound(mc); mc = new MathContext(x.Precision); if (res.CompareTo(p) > 0) { /* pi<x<=2pi: sin(x)= - sin(x-pi) */ return Sin(SubtractRound(res, p)).Negate(); } if (res.Multiply(BigDecimal.ValueOf(2)).CompareTo(p) > 0) { /* pi/2<x<=pi: sin(x)= sin(pi-x) */ return Sin(SubtractRound(p, res)); } /* for the range 0<=x<Pi/2 one could use sin(2x)=2sin(x)cos(x) * to split this further. Here, use the sine up to pi/4 and the cosine higher up. */ if (res.Multiply(BigDecimal.ValueOf(4)).CompareTo(p) > 0) { /* x>pi/4: sin(x) = cos(pi/2-x) */ return Cos(SubtractRound(p.Divide(BigDecimal.ValueOf(2)), res)); } /* Simple Taylor expansion, sum_{i=1..infinity} (-1)^(..)res^(2i+1)/(2i+1)! */ BigDecimal resul = res; /* x^i */ BigDecimal xpowi = res; /* 2i+1 factorial */ BigInteger ifac = BigInteger.One; /* The error in the result is set by the error in x itself. */ double xUlpDbl = res.Ulp().ToDouble(); /* The error in the result is set by the error in x itself. * We need at most k terms to squeeze x^(2k+1)/(2k+1)! below this value. * x^(2k+1) < x.ulp; (2k+1)*log10(x) < -x.precision; 2k*log10(x)< -x.precision; * 2k*(-log10(x)) > x.precision; 2k*log10(1/x) > x.precision */ int k = (int) (res.Precision/System.Math.Log10(1.0/res.ToDouble()))/2; var mcTay = new MathContext(ErrorToPrecision(res.ToDouble(), xUlpDbl/k)); for (int i = 1;; i++) { /* TBD: at which precision will 2*i or 2*i+1 overflow? */ ifac = ifac.Multiply(BigInteger.ValueOf(2*i)); ifac = ifac.Multiply(BigInteger.ValueOf((2*i + 1))); xpowi = xpowi.Multiply(res).Multiply(res).Negate(); BigDecimal corr = xpowi.Divide(new BigDecimal(ifac), mcTay); resul = resul.Add(corr); if (corr.Abs().ToDouble() < 0.5*xUlpDbl) break; } /* The error in the result is set by the error in x itself. */ mc = new MathContext(res.Precision); return resul.Round(mc); }
public static BigDecimal Sqrt(BigDecimal x) { if (x.CompareTo(BigDecimal.Zero) < 0) throw new ArithmeticException("negative argument " + x + " of square root"); return Root(2, x); }
public int CompareTo(RealNumber other) { return(Value.CompareTo(other.Value)); }
public static BigDecimal Pow(BigDecimal x, BigDecimal y) { if (x.CompareTo(BigDecimal.Zero) < 0) throw new ArithmeticException("Cannot power negative " + x); if (x.CompareTo(BigDecimal.Zero) == 0) return BigDecimal.Zero; /* return x^y = exp(y*log(x)) ; */ BigDecimal logx = Log(x); BigDecimal ylogx = y.Multiply(logx); BigDecimal resul = Exp(ylogx); /* The estimation of the relative error in the result is |log(x)*err(y)|+|y*err(x)/x| */ double errR = System.Math.Abs(logx.ToDouble())*y.Ulp().ToDouble()/2d + System.Math.Abs(y.ToDouble()*x.Ulp().ToDouble()/2d/x.ToDouble()); var mcR = new MathContext(ErrorToPrecision(1.0, errR)); return resul.Round(mcR); }
protected override int UnsafeCompareTo(Dynamic other) { return(value.CompareTo(other.AsBigDecimal)); }
public static BigDecimal PowRound(BigDecimal x, Rational q) { /** Special cases: x^1=x and x^0 = 1 */ if (q.CompareTo(BigInteger.One) == 0) return x; if (q.Sign == 0) return BigDecimal.One; if (q.IsInteger) { /* We are sure that the denominator is positive here, because normalize() has been * called during constrution etc. */ return PowRound(x, q.Numerator); } /* Refuse to operate on the general negative basis. The integer q have already been handled above. */ if (x.CompareTo(BigDecimal.Zero) < 0) throw new ArithmeticException("Cannot power negative " + x); if (q.IsIntegerFraction) { /* Newton method with first estimate in double precision. * The disadvantage of this first line here is that the result must fit in the * standard range of double precision numbers exponents. */ double estim = System.Math.Pow(x.ToDouble(), q.ToDouble()); var res = new BigDecimal(estim); /* The error in x^q is q*x^(q-1)*Delta(x). * The relative error is q*Delta(x)/x, q times the relative error of x. */ var reserr = new BigDecimal(0.5*q.Abs().ToDouble() *x.Ulp().Divide(x.Abs(), MathContext.Decimal64).ToDouble()); /* The main point in branching the cases above is that this conversion * will succeed for numerator and denominator of q. */ int qa = q.Numerator.ToInt32(); int qb = q.Denominator.ToInt32(); /* Newton iterations. */ BigDecimal xpowa = PowRound(x, qa); for (;;) { /* numerator and denominator of the Newton term. The major * disadvantage of this implementation is that the updates of the powers * of the new estimate are done in full precision calling BigDecimal.pow(), * which becomes slow if the denominator of q is large. */ BigDecimal nu = res.Pow(qb).Subtract(xpowa); BigDecimal de = MultiplyRound(res.Pow(qb - 1), q.Denominator); /* estimated correction */ BigDecimal eps = nu.Divide(de, MathContext.Decimal64); BigDecimal err = res.Multiply(reserr, MathContext.Decimal64); int precDiv = 2 + ErrorToPrecision(eps, err); if (precDiv <= 0) { /* The case when the precision is already reached and any precision * will do. */ eps = nu.Divide(de, MathContext.Decimal32); } else { eps = nu.Divide(de, new MathContext(precDiv)); } res = SubtractRound(res, eps); /* reached final precision if the relative error fell below reserr, * |eps/res| < reserr */ if (eps.Divide(res, MathContext.Decimal64).Abs().CompareTo(reserr) < 0) { /* delete the bits of extra precision kept in this * working copy. */ return res.Round(new MathContext(ErrorToPrecision(reserr.ToDouble()))); } } } /* The error in x^q is q*x^(q-1)*Delta(x) + Delta(q)*x^q*log(x). * The relative error is q/x*Delta(x) + Delta(q)*log(x). Convert q to a floating point * number such that its relative error becomes negligible: Delta(q)/q << Delta(x)/x/log(x) . */ int precq = 3 + ErrorToPrecision((x.Ulp().Divide(x, MathContext.Decimal64)).ToDouble() /System.Math.Log(x.ToDouble())); /* Perform the actual calculation as exponentiation of two floating point numbers. */ return Pow(x, q.ToBigDecimal(new MathContext(precq))); }
/// <summary> /// Compares the value of this AseDecimal with the AseDecimal value. /// </summary> public int CompareTo(AseDecimal value) { return(Backing.CompareTo(value.Backing)); }
public static BigDecimal Root(int n, BigDecimal x) { if (x.CompareTo(BigDecimal.Zero) < 0) throw new ArithmeticException("negative argument " + x + " of root"); if (n <= 0) throw new ArithmeticException("negative power " + n + " of root"); if (n == 1) return x; /* start the computation from a double precision estimate */ var s = new BigDecimal(System.Math.Pow(x.ToDouble(), 1.0/n)); /* this creates nth with nominal precision of 1 digit */ var nth = new BigDecimal(n); /* Specify an internal accuracy within the loop which is * slightly larger than what is demanded by 'eps' below. */ BigDecimal xhighpr = ScalePrecision(x, 2); var mc = new MathContext(2 + x.Precision); /* Relative accuracy of the result is eps. */ double eps = x.Ulp().ToDouble()/(2*n*x.ToDouble()); for (;;) { /* s = s -(s/n-x/n/s^(n-1)) = s-(s-x/s^(n-1))/n; test correction s/n-x/s for being * smaller than the precision requested. The relative correction is (1-x/s^n)/n, */ BigDecimal c = xhighpr.Divide(s.Pow(n - 1), mc); c = s.Subtract(c); var locmc = new MathContext(c.Precision); c = c.Divide(nth, locmc); s = s.Subtract(c); if (System.Math.Abs(c.ToDouble()/s.ToDouble()) < eps) break; } return s.Round(new MathContext(ErrorToPrecision(eps))); }