Beispiel #1
0
        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));
        }
Beispiel #2
0
        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);
        }
Beispiel #6
0
        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");
        }
Beispiel #7
0
        public BigFloat Divide(BigFloat divisor, MathContext mc)
        {
            BigFloat ret = this.Divide(divisor);

            // TODO: mc?
            return(ret);
        }
Beispiel #8
0
 /// <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;
 }
Beispiel #9
0
        /**
         * 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;
        }
Beispiel #12
0
 /// <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;
 }
Beispiel #13
0
 public AggregationMethodFactoryAvg(ExprAvgNode parent, Type childType, MathContext optionalMathContext)
 {
     Parent              = parent;
     ChildType           = childType;
     ResultType          = GetAvgAggregatorType(childType);
     OptionalMathContext = optionalMathContext;
 }
Beispiel #14
0
        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());
        }
Beispiel #15
0
 public AggregationMethodFactory MakeAvg(
     StatementExtensionSvcContext statementExtensionSvcContext,
     ExprAvgNode exprAvgNode,
     Type childType,
     MathContext optionalMathContext)
 {
     return(new AggregationMethodFactoryAvg(exprAvgNode, childType, optionalMathContext));
 }
Beispiel #16
0
 public EnumAverageDecimalScalarForge(
     int streamCountIncoming,
     MathContext optionalMathContext)
     : base(
         streamCountIncoming)
 {
     _optionalMathContext = optionalMathContext;
 }
Beispiel #17
0
 public EnumAverageDecimalEventsForge(
     ExprForge innerExpression,
     int streamCountIncoming,
     MathContext optionalMathContext)
     : base(innerExpression, streamCountIncoming)
 {
     this.optionalMathContext = optionalMathContext;
 }
Beispiel #18
0
        /**
         * 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;
 }
Beispiel #22
0
        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);
        }
Beispiel #23
0
        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));
        }
Beispiel #26
0
        /// <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);
        }
Beispiel #27
0
        /**
         * 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));
        }
Beispiel #28
0
        /**
         * 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));
        }
Beispiel #29
0
 public EnumAverageDecimalScalarLambdaForge(
     ExprForge innerExpression,
     int streamCountIncoming,
     ObjectArrayEventType resultEventType,
     MathContext optionalMathContext)
     : base(innerExpression, streamCountIncoming)
 {
     this.resultEventType = resultEventType;
     this.optionalMathContext = optionalMathContext;
 }
Beispiel #30
0
        /**
         * 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));
        }
Beispiel #31
0
 public AggregationFactoryMethodAvg(
     ExprAvgNode parent,
     Type childType,
     MathContext optionalMathContext)
 {
     this.parent = parent;
     this.childType = childType;
     resultType = GetAvgAggregatorType(childType);
     this.optionalMathContext = optionalMathContext;
 }
Beispiel #32
0
        /**
         * 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));
        }
Beispiel #33
0
        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));
        }
Beispiel #35
0
 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());
 }
Beispiel #36
0
        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);
        }
Beispiel #37
0
        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);
        }
Beispiel #38
0
 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);
 }
Beispiel #39
0
        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);
        }
Beispiel #40
0
        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);
        }
Beispiel #41
0
        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);
        }
Beispiel #42
0
        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);
        }
Beispiel #43
0
        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);
        }
Beispiel #44
0
        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);
            }
        }
Beispiel #45
0
        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);
            }
        }
Beispiel #46
0
 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());
     }
 }
Beispiel #47
0
 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);
 }
Beispiel #48
0
 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);
 }
Beispiel #49
0
        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);
        }
Beispiel #50
0
 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);
 }
Beispiel #51
0
 public override MathValue Evaluate(MathContext context)
 {
     return context.Get(_name);
 }
Beispiel #52
0
        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);
        }
Beispiel #53
0
 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);
 }
Beispiel #54
0
 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());
 }
Beispiel #55
0
        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);
        }
Beispiel #56
0
 public BigDecimal Abs(MathContext mc)
 {
     return BigMath.Sqrt(Norm(), mc);
 }
Beispiel #57
0
        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);
            }
        }
Beispiel #58
0
 public BigComplex Divide(BigComplex oth, MathContext mc)
 {
     /* lazy implementation: (x+iy)/(a+ib)= (x+iy)* 1/(a+ib) */
     return Multiply(oth.Inverse(mc), mc);
 }
Beispiel #59
0
        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);
            }
        }
Beispiel #60
0
        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);
        }