public void Register(MathContext context) { context.SetNameValue("e", new MathNumber(Math.E)); context.SetNameValue("ln10", new MathNumber(Math.Log(10))); context.SetNameValue("ln2", new MathNumber(Math.Log(2))); context.SetNameValue("log2e", new MathNumber(1 / Math.Log(2))); context.SetNameValue("log10e", new MathNumber(1 / Math.Log(10))); context.SetNameValue("pi", new MathNumber(Math.PI)); context.SetNameValue("sqrt1_2", new MathNumber(Math.Sqrt(.5))); context.SetNameValue("sqrt2", new MathNumber(Math.Sqrt(2))); context.Register("abs", CreateFunction(Math.Abs)); context.Register("acos", CreateFunction(Math.Acos)); context.Register("asin", CreateFunction(Math.Asin)); context.Register("atan", CreateFunction(Math.Atan)); context.Register("ceil", CreateFunction(Math.Ceiling)); context.Register("cos", CreateFunction(Math.Cos)); context.Register("exp", CreateFunction(Math.Exp)); context.Register("floor", CreateFunction(Math.Floor)); context.Register("log", CreateFunction(Math.Log)); context.Register("random", args => new MathNumber(_random.NextDouble())); context.Register("round", CreateFunction(Math.Round)); context.Register("sin", CreateFunction(Math.Sin)); context.Register("sqrt", CreateFunction(Math.Sqrt)); context.Register("tan", CreateFunction(Math.Tan)); context.Register("atan2", CreateFunction2(Math.Atan2)); context.Register("pow", CreateFunction2(Math.Pow)); }
public PowerTwoNPlusOneIterator(BigDecimal x, MathContext mathContext) { this.mathContext = mathContext; xPowerTwo = x.multiply(x, mathContext); powerOfX = x; }
public IScheduler GetCurrentScheduler() { MathContext ctx = MathContext.Current; Guid currentId = ctx.InstanceId; lock (_schedulerStack) { IScheduler scheduler; if (_schedulerStack.TryGetValue(ctx.InstanceId, out scheduler)) { return(scheduler); } while (ctx.HasParent) { ctx = ctx.ParentContext; if (_schedulerStack.TryGetValue(ctx.InstanceId, out scheduler)) { return(scheduler); } } scheduler = new ImmediateScheduler(); _schedulerStack.Add(currentId, scheduler); return(scheduler); } }
/// <param name="mContext"> Precision setting for computing the quadrature rules. </param> public LegendreHighPrecisionRuleFactory(MathContext mContext) { this.mContext = mContext; two = new decimal("2", mContext); minusOne = new decimal("-1", mContext); oneHalf = new decimal("0.5", mContext); }
public PowerTwoNMinusOneIterator(BigDecimal x, MathContext mathContext) { this.mathContext = mathContext; xPowerTwo = x.multiply(x, mathContext); powerOfX = BigDecimalMath.reciprocal(x, mathContext); }
public void MathContextStacking() { MathContext c1 = MathContext.Current; Assert.IsNotNull(c1, "01"); Assert.AreNotEqual(Guid.Empty, c1.InstanceId, "02"); Guid id1 = c1.InstanceId; Assert.AreEqual(id1, MathContext.Current.InstanceId, "03"); Assert.AreEqual(false, c1.HasParent, "04"); Assert.IsNull(c1.ParentContext, "05"); using (MathContext c2 = MathContext.Create()) { Assert.IsNotNull(c2, "06"); Assert.AreNotEqual(Guid.Empty, c2.InstanceId, "07"); Assert.AreNotEqual(c1.InstanceId, c2.InstanceId, "08"); Assert.AreEqual(true, c2.HasParent, "09"); Assert.AreEqual(c1.InstanceId, c2.ParentContext.InstanceId, "10"); Assert.AreEqual(id1, c1.InstanceId, "11"); Assert.AreEqual(c2.InstanceId, MathContext.Current.InstanceId, "12"); } Assert.AreEqual(id1, MathContext.Current.InstanceId, "13"); Assert.AreEqual(id1, c1.InstanceId, "14"); }
public BigFloat Divide(BigFloat divisor, MathContext mc) { BigFloat ret = this.Divide(divisor); // TODO: mc? return(ret); }
/// <summary> /// Ctor. /// </summary> /// <param name="divisionByZeroReturnsNull">false for division-by-zero returns infinity, true for null</param> /// <param name="mathContext">math context</param> public DivideDecimalWMathContext( bool divisionByZeroReturnsNull, MathContext mathContext) { this._divisionByZeroReturnsNull = divisionByZeroReturnsNull; this._mathContext = mathContext; }
/** * Calculates {@link BigComplex} x to the power of <code>long</code> y (x<sup>y</sup>). * * <p>The implementation tries to minimize the number of multiplications of {@link BigComplex x} (using squares whenever possible).</p> * * <p>See: <a href="https://en.wikipedia.org/wiki/Exponentiation#Efficient_computation_with_integer_exponents">Wikipedia: Exponentiation - efficient computation</a></p> * * @param x the {@link BigComplex} value to take to the power * @param y the <code>long</code> 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 <code>mathContext</code> */ public static BigComplex pow(this BigComplex x, long y, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 10, mathContext.getRoundingMode()); if (y < 0) { return(BigComplex.ONE.divide(pow(x, -y, mc), mc).round(mathContext)); } BigComplex result = BigComplex.ONE; while (y > 0) { if ((y & 1) == 1) { // odd exponent -> multiply result with x result = result.multiply(x, mc); y -= 1; } if (y > 0) { // even exponent -> square x x = x.multiply(x, mc); } y >>= 1; } return(result.round(mathContext)); }
public PowerNIterator(BigDecimal x, MathContext mathContext) { this.x = x; this.mathContext = mathContext; powerOfX = BigDecimal.ONE; }
public PowerTwoNIterator(BigDecimal x, MathContext mathContext) { this.mathContext = mathContext; xPowerTwo = x.multiply(x, mathContext); powerOfX = BigDecimal.ONE; }
/// <summary> /// Ctor /// </summary> /// <param name="allowExtendedAggregationFunc">true to allow non-SQL standard builtin agg functions.</param> /// <param name="isUdfCache">if set to <c>true</c> [is udf cache].</param> /// <param name="isDuckType">if set to <c>true</c> [is duck type].</param> /// <param name="sortUsingCollator">if set to <c>true</c> [sort using collator].</param> /// <param name="optionalDefaultMathContext">The optional default math context.</param> /// <param name="timeZone"></param> /// <param name="threadingProfile"></param> /// <param name="aggregationFactoryFactory"></param> public EngineImportServiceImpl( bool allowExtendedAggregationFunc, bool isUdfCache, bool isDuckType, bool sortUsingCollator, MathContext optionalDefaultMathContext, TimeZoneInfo timeZone, ConfigurationEngineDefaults.ThreadingProfile threadingProfile, AggregationFactoryFactory aggregationFactoryFactory) { _imports = new List <AutoImportDesc>(); _annotationImports = new List <AutoImportDesc>(); _aggregationFunctions = new Dictionary <String, ConfigurationPlugInAggregationFunction>(); _aggregationAccess = new List <Pair <ISet <String>, ConfigurationPlugInAggregationMultiFunction> >(); _singleRowFunctions = new Dictionary <String, EngineImportSingleRowDesc>(); _methodInvocationRef = new Dictionary <String, ConfigurationMethodRef>(); _allowExtendedAggregationFunc = allowExtendedAggregationFunc; IsUdfCache = isUdfCache; IsDuckType = isDuckType; _sortUsingCollator = sortUsingCollator; _optionalDefaultMathContext = optionalDefaultMathContext; _timeZone = timeZone; _threadingProfile = threadingProfile; _aggregationFactoryFactory = aggregationFactoryFactory; }
public AggregationMethodFactoryAvg(ExprAvgNode parent, Type childType, MathContext optionalMathContext) { Parent = parent; ChildType = childType; ResultType = GetAvgAggregatorType(childType); OptionalMathContext = optionalMathContext; }
private static Computer MakeDecimalComputer( MathArithTypeEnum operation, Type typeOne, Type typeTwo, bool divisionByZeroReturnsNull, MathContext optionalMathContext) { if (typeOne.IsDecimal() && typeTwo.IsDecimal()) { if (operation == MathArithTypeEnum.DIVIDE) { if (optionalMathContext != null) { return(new DivideDecimalWMathContext(divisionByZeroReturnsNull, optionalMathContext)); } return(new DivideDecimal(divisionByZeroReturnsNull)); } return(computers.Get(new MathArithDesc(typeof(decimal?), operation))); } var convertorOne = SimpleNumberCoercerFactory.GetCoercer(typeOne, typeof(decimal?)); var convertorTwo = SimpleNumberCoercerFactory.GetCoercer(typeTwo, typeof(decimal?)); if (operation == MathArithTypeEnum.ADD) { return(new AddDecimalConvComputer(convertorOne, convertorTwo)); } if (operation == MathArithTypeEnum.SUBTRACT) { return(new SubtractDecimalConvComputer(convertorOne, convertorTwo)); } if (operation == MathArithTypeEnum.MULTIPLY) { return(new MultiplyDecimalConvComputer(convertorOne, convertorTwo)); } if (operation == MathArithTypeEnum.DIVIDE) { if (optionalMathContext == null) { return(new DivideDecimalConvComputerNoMathCtx( convertorOne, convertorTwo, divisionByZeroReturnsNull)); } return(new DivideDecimalConvComputerWithMathCtx( convertorOne, convertorTwo, divisionByZeroReturnsNull, optionalMathContext)); } return(new ModuloDouble()); }
public AggregationMethodFactory MakeAvg( StatementExtensionSvcContext statementExtensionSvcContext, ExprAvgNode exprAvgNode, Type childType, MathContext optionalMathContext) { return(new AggregationMethodFactoryAvg(exprAvgNode, childType, optionalMathContext)); }
public EnumAverageDecimalScalarForge( int streamCountIncoming, MathContext optionalMathContext) : base( streamCountIncoming) { _optionalMathContext = optionalMathContext; }
public EnumAverageDecimalEventsForge( ExprForge innerExpression, int streamCountIncoming, MathContext optionalMathContext) : base(innerExpression, streamCountIncoming) { this.optionalMathContext = optionalMathContext; }
/** * Calculates the cosine (cosinus) of {@link BigComplex} x in the complex domain. * * @param x the {@link BigComplex} to calculate the cosine for * @param mathContext the {@link MathContext} used for the result * @return the calculated cosine {@link BigComplex} with the precision specified in the <code>mathContext</code> */ public static BigComplex cos(this BigComplex x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); return(BigComplex.valueOf( BigDecimalMath.cos(x.re, mc).multiply(BigDecimalMath.cosh(x.im, mc), mc).round(mathContext), BigDecimalMath.sin(x.re, mc).multiply(BigDecimalMath.sinh(x.im, mc), mc).negate().round(mathContext))); }
public AggregationForgeFactoryAvg(ExprAvgNode parent, Type childType, DataInputOutputSerdeForge distinctSerde, MathContext optionalMathContext) { this.parent = parent; this.childType = childType; this.distinctSerde = distinctSerde; this.resultType = GetAvgAggregatorType(childType); this.optionalMathContext = optionalMathContext; }
public void AddWithContext(string a, int aScale, string b, int bScale, string c, int cScale, int precision, RoundingMode mode) { BigDecimal aNumber = new BigDecimal(BigInteger.Parse(a), aScale); BigDecimal bNumber = new BigDecimal(BigInteger.Parse(b), bScale); MathContext mc = new MathContext(precision, mode); BigDecimal result = aNumber.Add(bNumber, mc); Assert.AreEqual(c, result.ToString(), "incorrect value"); Assert.AreEqual(cScale, result.Scale, "incorrect scale"); }
public DivideDecimalConvComputerWithMathCtx( Coercer convOne, Coercer convTwo, bool divisionByZeroReturnsNull, MathContext mathContext) : base(convOne, convTwo, divisionByZeroReturnsNull) { _mathContext = mathContext; }
public override MathValue Evaluate(MathContext context) { var function = context.Get(_name) as MathFunction; if (function == null) throw new MathException("Invalid function name: " + _name); MathValue[] values = _args.Select(arg => arg.Evaluate(context)).ToArray(); return function.Function(values); }
public override MathValue Evaluate(MathContext context) { double value = Child.Evaluate(context).ToNumber(); if (double.IsNaN(value)) return new MathNumber(double.NaN); return new MathNumber(-value); }
public void CreateSimulationApartement(IScheduler scheduler) { MathContext ctx = MathContext.Current; lock (_schedulerStack) // don't interfer with GetCurrentScheduler { _schedulerStack.Add(ctx.InstanceId, scheduler); } }
public static BigDecimal FahrenheitToKexle(BigDecimal fahrenheit) { MathContext mcInt = new MathContext(9999, RoundingMode.Ceiling); BigDecimal f2 = fahrenheit.Subtract(27.0, mcInt); BigDecimal s1f2s3 = f2.Multiply(0.6, mcInt); BigDecimal s1f2 = new BigDecimal(2634.0).Divide(s1f2s3, mcInt); return(s1f2.Subtract(4.0, mcInt)); }
/// <summary> /// Divides decimals. /// </summary> /// <param name="d1">The d1.</param> /// <param name="d2">The d2.</param> /// <param name="optionalMathContext">The optional math context.</param> /// <returns></returns> public static object DivideDecimalUnchecked(object d1, object d2, MathContext optionalMathContext) { var nd1 = d1.AsDecimal(); var nd2 = d2.AsDecimal(); var ndx = nd1 / nd2; return(optionalMathContext != null ? Math.Round(ndx, optionalMathContext.Precision, optionalMathContext.RoundingMode) : ndx); }
/** * Calculates the natural logarithm of {@link BigComplex} x in the complex domain. * * <p>See: <a href="https://en.wikipedia.org/wiki/Complex_logarithm">Wikipedia: Complex logarithm</a></p> * * @param x the {@link BigComplex} to calculate the natural logarithm for * @param mathContext the {@link MathContext} used for the result * @return the calculated natural logarithm {@link BigComplex} with the precision specified in the <code>mathContext</code> */ public static BigComplex log(this BigComplex x, MathContext mathContext) { // https://en.wikipedia.org/wiki/Complex_logarithm MathContext mc1 = new MathContext(mathContext.getPrecision() + 20, mathContext.getRoundingMode()); MathContext mc2 = new MathContext(mathContext.getPrecision() + 5, mathContext.getRoundingMode()); return(BigComplex.valueOf( BigDecimalMath.log(x.abs(mc1), mc1).round(mathContext), x.angle(mc2)).round(mathContext)); }
/** * Calculates {@link BigComplex} x to the power of {@link BigDecimal} y (x<sup>y</sup>). * * @param x the {@link BigComplex} value to take to the power * @param y the {@link BigDecimal} value to serve as exponent * @param mathContext the {@link MathContext} used for the result * @return the calculated x to the power of y with the precision specified in the <code>mathContext</code> */ public static BigComplex pow(this BigComplex x, BigDecimal y, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); BigDecimal angleTimesN = x.angle(mc).multiply(y, mc); return(BigComplex.valueOf( BigDecimalMath.cos(angleTimesN, mc), BigDecimalMath.sin(angleTimesN, mc)).multiply(BigDecimalMath.pow(x.abs(mc), y, mc), mc).round(mathContext)); }
public EnumAverageDecimalScalarLambdaForge( ExprForge innerExpression, int streamCountIncoming, ObjectArrayEventType resultEventType, MathContext optionalMathContext) : base(innerExpression, streamCountIncoming) { this.resultEventType = resultEventType; this.optionalMathContext = optionalMathContext; }
/** * Calculates the natural exponent of {@link BigComplex} x (e<sup>x</sup>) in the complex domain. * * <p>See: <a href="https://en.wikipedia.org/wiki/Exponential_function#Complex_plane">Wikipedia: Exponent (Complex plane)</a></p> * * @param x the {@link BigComplex} to calculate the exponent for * @param mathContext the {@link MathContext} used for the result * @return the calculated exponent {@link BigComplex} with the precision specified in the <code>mathContext</code> */ public static BigComplex exp(this BigComplex x, MathContext mathContext) { MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); BigDecimal expRe = BigDecimalMath.exp(x.re, mc); return(BigComplex.valueOf( expRe.multiply(BigDecimalMath.cos(x.im, mc), mc).round(mathContext), expRe.multiply(BigDecimalMath.sin(x.im, mc), mc)).round(mathContext)); }
public AggregationFactoryMethodAvg( ExprAvgNode parent, Type childType, MathContext optionalMathContext) { this.parent = parent; this.childType = childType; resultType = GetAvgAggregatorType(childType); this.optionalMathContext = optionalMathContext; }
/** * Calculates the square root of {@link BigComplex} x in the complex domain (√x). * * <p>See <a href="https://en.wikipedia.org/wiki/Square_root#Square_root_of_an_imaginary_number">Wikipedia: Square root (Square root of an imaginary number)</a></p> * * @param x the {@link BigComplex} to calculate the square root for * @param mathContext the {@link MathContext} used for the result * @return the calculated square root {@link BigComplex} with the precision specified in the <code>mathContext</code> */ public static BigComplex sqrt(this BigComplex x, MathContext mathContext) { // https://math.stackexchange.com/questions/44406/how-do-i-get-the-square-root-of-a-complex-number MathContext mc = new MathContext(mathContext.getPrecision() + 4, mathContext.getRoundingMode()); BigDecimal magnitude = x.abs(mc); BigComplex a = x.add(magnitude, mc); return(a.divide(a.abs(mc), mc).multiply(BigDecimalMath.sqrt(magnitude, mc), mc).round(mathContext)); }
public void ParseExpression_CustomOperators_Exception(string expected) { MathContext context = new MathContext(); ITokenizer tokenizer = new Tokenizer(expected); IParser parser = new Parser(tokenizer, context); LangException exception = Assert.Throws <LangException>(() => parser.Parse()); Assert.AreEqual(LangException.ErrorCode.UNEXPECTED_TOKEN, exception.ErrorType); }
public TVector Substitute(MathContext context) { var evalTerms = new Dictionary <TBasis, IAlgebraicExpression>(); foreach (var term in this.Terms) { evalTerms.Add(term.Key, term.Value.Substitute(context)); } return(this.NewExplicitVectorValue(evalTerms)); }
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()); }
public static BigDecimal Hypot(int n, BigDecimal x) { /* compute n^2+x^2 in infinite precision */ BigDecimal z = (new BigDecimal(n)).Pow(2).Add(x.Pow(2)); /* Truncate to the precision set by x. Absolute error = in z (square of the result) is |2*x*xerr|, * where the error is 1/2 of the ulp. Two intermediate protection digits. * zerr is a signed value, but used only in conjunction with err2prec(), so this feature does not harm. */ double zerr = x.ToDouble()*x.Ulp().ToDouble(); var mc = new MathContext(2 + ErrorToPrecision(z.ToDouble(), zerr)); /* Pull square root */ z = Sqrt(z.Round(mc)); /* Final rounding. Absolute error in the square root is x*xerr/z, where zerr holds 2*x*xerr. */ mc = new MathContext(ErrorToPrecision(z.ToDouble(), 0.5*zerr/z.ToDouble())); return z.Round(mc); }
private static BigDecimal BroadhurstBbp(int n, int p, int[] a, MathContext mc) { /* Explore the actual magnitude of the result first with a quick estimate. */ double x = 0.0; for (int k = 1; k < 10; k++) x += a[(k - 1)%8]/System.Math.Pow(2d, p*(k + 1)/2d)/System.Math.Pow(k, n); /* Convert the relative precision and estimate of the result into an absolute precision. */ double eps = PrecisionToError(x, mc.Precision); /* Divide this through the number of terms in the sum to account for error accumulation * The divisor 2^(p(k+1)/2) means that on the average each 8th term in k has shrunk by * relative to the 8th predecessor by 1/2^(4p). 1/2^(4pc) = 10^(-precision) with c the 8term * cycles yields c=log_2( 10^precision)/4p = 3.3*precision/4p with k=8c */ var kmax = (int) (6.6*mc.Precision/p); /* Now eps is the absolute error in each term */ eps /= kmax; BigDecimal res = BigDecimal.Zero; for (int c = 0;; c++) { var r = new Rational(); for (int k = 0; k < 8; k++) { var tmp = new Rational(BigInteger.ValueOf(a[k]), (BigInteger.ValueOf((1 + 8*c + k))).Pow(n)); /* floor( (pk+p)/2) */ int pk1h = p*(2 + 8*c + k)/2; tmp = tmp.Divide(BigInteger.One.ShiftLeft(pk1h)); r = r.Add(tmp); } if (System.Math.Abs(r.ToDouble()) < eps) break; var mcloc = new MathContext(1 + ErrorToPrecision(r.ToDouble(), eps)); res = res.Add(r.ToBigDecimal(mcloc)); } return res.Round(mc); }
public static BigDecimal DivideRound(BigDecimal x, int n) { // The estimation of the relative error in the result is |err(x)/x| var mc = new MathContext(x.Precision); return x.Divide(new BigDecimal(n), 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 ModPi(BigDecimal x) { /* write x= pi*k+r with the precision in r defined by the precision of x and not * compromised by the precision of pi, so the ulp of pi*k should match the ulp of x. * First get a guess of k to figure out how many digits of pi are needed. */ var k = (int) (x.ToDouble()/System.Math.PI); /* want to have err(pi*k)< err(x)=x.ulp/2, so err(pi) = err(x)/(2k) with two safety digits */ double errpi; if (k != 0) errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble()/k); else errpi = 0.5*System.Math.Abs(x.Ulp().ToDouble()); var mc = new MathContext(2 + ErrorToPrecision(3.1416, errpi)); BigDecimal onepi = PiRound(mc); BigDecimal pihalf = onepi.Divide(new BigDecimal(2)); /* Delegate the actual operation to the BigDecimal class, which may return * a negative value of x was negative . */ BigDecimal res = x.Remainder(onepi); if (res.CompareTo(pihalf) > 0) res = res.Subtract(onepi); else if (res.CompareTo(pihalf.Negate()) < 0) res = res.Add(onepi); /* The actual precision is set by the input value, its absolute value of x.ulp()/2. */ mc = new MathContext(ErrorToPrecision(res.ToDouble(), x.Ulp().ToDouble()/2d)); return res.Round(mc); }
public static BigDecimal Exp(MathContext mc) { /* look it up if possible */ if (mc.Precision < E.Precision) return E.Round(mc); /* Instantiate a 1.0 with the requested pseudo-accuracy * and delegate the computation to the public method above. */ BigDecimal uni = ScalePrecision(BigDecimal.One, mc.Precision); return Exp(uni); }
public static BigDecimal Log(Rational r, MathContext mc) { /* the value is undefined if x is negative. */ if (r.CompareTo(Rational.Zero) <= 0) throw new ArithmeticException("Cannot take log of negative " + r); if (r.CompareTo(Rational.One) == 0) return BigDecimal.Zero; /* log(r+epsr) = log(r)+epsr/r. Convert the precision to an absolute error in the result. * eps contains the required absolute error of the result, epsr/r. */ double eps = PrecisionToError(System.Math.Log(r.ToDouble()), mc.Precision); /* Convert this further into a requirement of the relative precision in r, given that * epsr/r is also the relative precision of r. Add one safety digit. */ var mcloc = new MathContext(1 + ErrorToPrecision(eps)); BigDecimal resul = Log(r.ToBigDecimal(mcloc)); return resul.Round(mc); }
public static BigDecimal Mod2Pi(BigDecimal x) { /* write x= 2*pi*k+r with the precision in r defined by the precision of x and not * compromised by the precision of 2*pi, so the ulp of 2*pi*k should match the ulp of x. * First get a guess of k to figure out how many digits of 2*pi are needed. */ var k = (int) (0.5*x.ToDouble()/System.Math.PI); /* want to have err(2*pi*k)< err(x)=0.5*x.ulp, so err(pi) = err(x)/(4k) with two safety digits */ double err2pi; if (k != 0) err2pi = 0.25*System.Math.Abs(x.Ulp().ToDouble()/k); else err2pi = 0.5*System.Math.Abs(x.Ulp().ToDouble()); var mc = new MathContext(2 + ErrorToPrecision(6.283, err2pi)); BigDecimal twopi = PiRound(mc).Multiply(new BigDecimal(2)); /* Delegate the actual operation to the BigDecimal class, which may return * a negative value of x was negative . */ BigDecimal res = x.Remainder(twopi); if (res.CompareTo(BigDecimal.Zero) < 0) res = res.Add(twopi); /* The actual precision is set by the input value, its absolute value of x.ulp()/2. */ mc = new MathContext(ErrorToPrecision(res.ToDouble(), x.Ulp().ToDouble()/2d)); return res.Round(mc); }
public static BigDecimal Log(int n, MathContext mc) { /* the value is undefined if x is negative. */ if (n <= 0) throw new ArithmeticException("Cannot take log of negative " + n); if (n == 1) return BigDecimal.Zero; if (n == 2) { if (mc.Precision < Log2.Precision) return Log2.Round(mc); /* Broadhurst <a href="http://arxiv.org/abs/math/9803067">arXiv:math/9803067</a> * Error propagation: the error in log(2) is twice the error in S(2,-5,...). */ int[] a = {2, -5, -2, -7, -2, -5, 2, -3}; BigDecimal S = BroadhurstBbp(2, 1, a, new MathContext(1 + mc.Precision)); S = S.Multiply(new BigDecimal(8)); S = Sqrt(DivideRound(S, 3)); return S.Round(mc); } if (n == 3) { /* summation of a series roughly proportional to (7/500)^k. Estimate count * of terms to estimate the precision (drop the favorable additional * 1/k here): 0.013^k <= 10^(-precision), so k*log10(0.013) <= -precision * so k>= precision/1.87. */ var kmax = (int) (mc.Precision/1.87); var mcloc = new MathContext(mc.Precision + 1 + (int) (System.Math.Log10(kmax*0.693/1.098))); BigDecimal log3 = MultiplyRound(Log(2, mcloc), 19); /* log3 is roughly 1, so absolute and relative error are the same. The * result will be divided by 12, so a conservative error is the one * already found in mc */ double eps = PrecisionToError(1.098, mc.Precision)/kmax; var r = new Rational(7153, 524288); var pk = new Rational(7153, 524288); for (int k = 1;; k++) { Rational tmp = pk.Divide(k); if (tmp.ToDouble() < eps) break; /* how many digits of tmp do we need in the sum? */ mcloc = new MathContext(ErrorToPrecision(tmp.ToDouble(), eps)); BigDecimal c = pk.Divide(k).ToBigDecimal(mcloc); if (k%2 != 0) log3 = log3.Add(c); else log3 = log3.Subtract(c); pk = pk.Multiply(r); } log3 = DivideRound(log3, 12); return log3.Round(mc); } if (n == 5) { /* summation of a series roughly proportional to (7/160)^k. Estimate count * of terms to estimate the precision (drop the favorable additional * 1/k here): 0.046^k <= 10^(-precision), so k*log10(0.046) <= -precision * so k>= precision/1.33. */ var kmax = (int) (mc.Precision/1.33); var mcloc = new MathContext(mc.Precision + 1 + (int) (System.Math.Log10(kmax*0.693/1.609))); BigDecimal log5 = MultiplyRound(Log(2, mcloc), 14); /* log5 is roughly 1.6, so absolute and relative error are the same. The * result will be divided by 6, so a conservative error is the one * already found in mc */ double eps = PrecisionToError(1.6, mc.Precision)/kmax; var r = new Rational(759, 16384); var pk = new Rational(759, 16384); for (int k = 1;; k++) { Rational tmp = pk.Divide(k); if (tmp.ToDouble() < eps) break; /* how many digits of tmp do we need in the sum? */ mcloc = new MathContext(ErrorToPrecision(tmp.ToDouble(), eps)); BigDecimal c = pk.Divide(k).ToBigDecimal(mcloc); log5 = log5.Subtract(c); pk = pk.Multiply(r); } log5 = DivideRound(log5, 6); return log5.Round(mc); } if (n == 7) { /* summation of a series roughly proportional to (1/8)^k. Estimate count * of terms to estimate the precision (drop the favorable additional * 1/k here): 0.125^k <= 10^(-precision), so k*log10(0.125) <= -precision * so k>= precision/0.903. */ var kmax = (int) (mc.Precision/0.903); var mcloc = new MathContext(mc.Precision + 1 + (int) (System.Math.Log10(kmax*3*0.693/1.098))); BigDecimal log7 = MultiplyRound(Log(2, mcloc), 3); /* log7 is roughly 1.9, so absolute and relative error are the same. */ double eps = PrecisionToError(1.9, mc.Precision)/kmax; var r = new Rational(1, 8); var pk = new Rational(1, 8); for (int k = 1;; k++) { Rational tmp = pk.Divide(k); if (tmp.ToDouble() < eps) break; /* how many digits of tmp do we need in the sum? */ mcloc = new MathContext(ErrorToPrecision(tmp.ToDouble(), eps)); BigDecimal c = pk.Divide(k).ToBigDecimal(mcloc); log7 = log7.Subtract(c); pk = pk.Multiply(r); } return log7.Round(mc); } else { /* At this point one could either forward to the log(BigDecimal) signature (implemented) * or decompose n into Ifactors and use an implemenation of all the prime bases. * Estimate of the result; convert the mc argument to an absolute error eps * log(n+errn) = log(n)+errn/n = log(n)+eps */ double res = System.Math.Log(n); double eps = PrecisionToError(res, mc.Precision); /* errn = eps*n, convert absolute error in result to requirement on absolute error in input */ eps *= n; /* Convert this absolute requirement of error in n to a relative error in n */ var mcloc = new MathContext(1 + ErrorToPrecision(n, eps)); /* Padd n with a number of zeros to trigger the required accuracy in * the standard signature method */ BigDecimal nb = ScalePrecision(new BigDecimal(n), mcloc); return Log(nb); } }
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 BigComplex InvertRound(BigComplex z) { if (z.Imaginary.CompareTo(BigDecimal.Zero) == 0) { /* In this case with vanishing Im(x), the result is simply 1/Re z. */ MathContext mc = new MathContext(z.Real.Precision); return new BigComplex(BigDecimal.One.Divide(z.Real, mc)); } else if (z.Real.CompareTo(BigDecimal.Zero) == 0) { /* In this case with vanishing Re(z), the result is simply -i/Im z */ MathContext mc = new MathContext(z.Imaginary.Precision); return new BigComplex(BigDecimal.Zero, BigDecimal.One.Divide(z.Imaginary, mc).Negate()); } else { /* 1/(x.re+I*x.im) = 1/(x.re+x.im^2/x.re) - I /(x.im +x.re^2/x.im) */ BigDecimal R = AddRound(z.Real, DivideRound(MultiplyRound(z.Imaginary, z.Imaginary), z.Real)); BigDecimal I = AddRound(z.Imaginary, DivideRound(MultiplyRound(z.Real, z.Real), z.Imaginary)); MathContext mc = new MathContext(1 + R.Precision); R = BigDecimal.One.Divide(R, mc); mc = new MathContext(1 + I.Precision); I = BigDecimal.One.Divide(I, mc); return new BigComplex(R, I.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 MultiplyRound(BigDecimal x, BigInteger n) { BigDecimal resul = x.Multiply(new BigDecimal(n)); // The estimation of the absolute error in the result is |n*err(x)| var mc = new MathContext(n.CompareTo(BigInteger.Zero) != 0 ? x.Precision : 0); return resul.Round(mc); }
public static BigDecimal GammaRound(MathContext mc) { if (mc.Precision < Gamma.Precision) return Gamma.Round(mc); double eps = PrecisionToError(0.577, mc.Precision); // Euler-Stieltjes as shown in Dilcher, Aequat Math 48 (1) (1994) 55-85 var mcloc = new MathContext(2 + mc.Precision); BigDecimal resul = BigDecimal.One; resul = resul.Add(Log(2, mcloc)); resul = resul.Subtract(Log(3, mcloc)); // how many terms: zeta-1 falls as 1/2^(2n+1), so the // terms drop faster than 1/2^(4n+2). Set 1/2^(4kmax+2) < eps. // Leading term zeta(3)/(4^1*3) is 0.017. Leading zeta(3) is 1.2. Log(2) is 0.7 var kmax = (int) ((System.Math.Log(eps/0.7) - 2.0)/4d); mcloc = new MathContext(1 + ErrorToPrecision(1.2, eps/kmax)); for (int n = 1;; n++) { // zeta is close to 1. Division of zeta-1 through // 4^n*(2n+1) means divion through roughly 2^(2n+1) BigDecimal c = Zeta(2*n + 1, mcloc).Subtract(BigDecimal.One); BigInteger fourn = BigInteger.ValueOf(2*n + 1); fourn = fourn.ShiftLeft(2*n); c = DivideRound(c, fourn); resul = resul.Subtract(c); if (c.ToDouble() < 0.1*eps) break; } return resul.Round(mc); }
public static BigDecimal MultiplyRound(BigDecimal x, BigDecimal y) { BigDecimal resul = x.Multiply(y); // The estimation of the relative error in the result is the sum of the relative // errors |err(y)/y|+|err(x)/x| var mc = new MathContext(System.Math.Min(x.Precision, y.Precision)); return resul.Round(mc); }
public override MathValue Evaluate(MathContext context) { return context.Get(_name); }
public static BigDecimal MultiplyRound(BigDecimal x, Rational f) { if (f.CompareTo(BigInteger.Zero) == 0) return BigDecimal.Zero; /* Convert the rational value with two digits of extra precision */ var mc = new MathContext(2 + x.Precision); BigDecimal fbd = f.ToBigDecimal(mc); /* and the precision of the product is then dominated by the precision in x */ return MultiplyRound(x, fbd); }
public static BigDecimal DivideRound(BigDecimal x, BigDecimal y) { /* The estimation of the relative error in the result is |err(y)/y|+|err(x)/x| */ var mc = new MathContext(System.Math.Min(x.Precision, y.Precision)); BigDecimal resul = x.Divide(y, mc); /* If x and y are precise integer values that may have common factors, * the method above will truncate trailing zeros, which may result in * a smaller apparent accuracy than starte... add missing trailing zeros now. */ return ScalePrecision(resul, mc); }
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 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 BigDecimal Abs(MathContext mc) { return BigMath.Sqrt(Norm(), mc); }
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 BigComplex Divide(BigComplex oth, MathContext mc) { /* lazy implementation: (x+iy)/(a+ib)= (x+iy)* 1/(a+ib) */ return Multiply(oth.Inverse(mc), mc); }
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 Hypot(BigDecimal x, BigDecimal y) { /* compute x^2+y^2 */ BigDecimal z = x.Pow(2).Add(y.Pow(2)); /* truncate to the precision set by x and y. Absolute error = 2*x*xerr+2*y*yerr, * where the two errors are 1/2 of the ulp's. Two intermediate protectio digits. */ BigDecimal zerr = x.Abs().Multiply(x.Ulp()).Add(y.Abs().Multiply(y.Ulp())); var mc = new MathContext(2 + ErrorToPrecision(z, zerr)); /* Pull square root */ z = Sqrt(z.Round(mc)); /* Final rounding. Absolute error in the square root is (y*yerr+x*xerr)/z, where zerr holds 2*(x*xerr+y*yerr). */ mc = new MathContext(ErrorToPrecision(z.ToDouble(), 0.5*zerr.ToDouble()/z.ToDouble())); return z.Round(mc); }