Beispiel #1
0
        private static DecimalX lnNewton(DecimalX x, int scale)
        {
            DecimalX term;

            var sp1 = scale + 1;
            var n   = x;

            // Convergence tolerance = 5*(10^-(scale+1))
            var tolerance = DecimalX.Create(5);

            tolerance = tolerance.MovePointLeft(sp1);

            // Loop until the approximations converge
            // (two successive approximations are within the tolerance).
            do
            {
                // e^x
                var eToX = x.Exp(sp1);

                // (e^x - n)/e^x
                term = eToX.Subtract(n).CDivide(eToX, sp1, RoundingMode.Down);

                // x - (e^x - n)/e^x
                x = x.Subtract(term);
            } while (term.CompareTo(tolerance) > 0);

            x = DecimalX.Rescale(x, -scale, RoundingMode.HalfEven);
            return(x);
        }
Beispiel #2
0
        /// <summary>
        /// Compute e^x to a given scale. <br />Break x into its whole and
        /// fraction parts and compute (e^(1 + fraction/whole))^whole using
        /// Taylor's formula.
        /// </summary>
        /// <param name="scale">
        /// the desired <c>scale</c> of the result. (where the <c>scale</c> is
        /// the number of digits to the right of the decimal point.
        /// </param>
        /// <returns>
        /// the result value
        /// </returns>
        /// <exception cref="ArgumentException">
        /// if <c>scale</c> &lt;= 0.
        /// </exception>
        public static DecimalX Exp(this DecimalX x, int scale)
        {
            if (scale <= 0)
            {
                throw new ArgumentException(InvalidScale2);
            }

            if (x.Signum() == 0)
            {
                return(DecimalX.Create(1));
            }

            if (x.Signum() == -1)
            {
                var a = DecimalX.Create(1);
                return(a.CDivide(x.Negate().Exp(scale), scale, RoundingMode.HalfEven));
            }

            // Compute the whole part of x.
            var xWhole = DecimalX.Rescale(x, 0, RoundingMode.Down);

            // If there isn't a whole part, compute and return e^x.
            if (xWhole.Signum() == 0)
            {
                return(expTaylor(x, scale));
            }

            // Compute the fraction part of x.
            var xFraction = x.Subtract(xWhole);

            // z = 1 + fraction/whole
            var b = DecimalX.Create(1);
            var z = b.Add(xFraction.CDivide(xWhole, scale, RoundingMode.HalfEven));

            // t = e^z
            var t = expTaylor(z, scale);

            var maxLong = DecimalX.Create(long.MaxValue);
            var tempRes = DecimalX.Create(1);

            // Compute and return t^whole using IntPower().
            // If whole > Int64.MaxValue, then first compute products
            // of e^Int64.MaxValue.
            while (xWhole.CompareTo(maxLong) >= 0)
            {
                tempRes = tempRes.Multiply(t.IntPower(long.MaxValue, scale));
                tempRes = DecimalX.Rescale(tempRes, -scale, RoundingMode.HalfEven);
                xWhole  = xWhole.Subtract(maxLong);
            }

            var result = tempRes.Multiply(t.IntPower(xWhole.ToLong(), scale));

            return(DecimalX.Rescale(result, -scale, RoundingMode.HalfEven));
        }
Beispiel #3
0
        /// <summary>
        /// Compute the integral root of x to a given scale, x &gt;= 0 Using
        /// Newton's algorithm.
        /// </summary>
        /// <param name="index">
        /// the integral root value
        /// </param>
        /// <param name="scale">
        /// the desired <c>scale</c> of the result. (where the <c>scale</c> is
        /// the number of digits to the right of the decimal point.
        /// </param>
        /// <returns>
        /// the result value
        /// </returns>
        /// <exception cref="ArgumentException">
        /// if <c>scale</c> &lt; 0.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// if <c>self</c> &lt; 0.
        /// </exception>
        public static DecimalX IntRoot(this DecimalX x, long index, int scale)
        {
            DecimalX xPrev;

            if (scale < 0)
            {
                throw new ArgumentException(InvalidScale);
            }

            if (x.Signum() < 0)
            {
                throw new ArgumentException(NegativeIntRoot);
            }

            var sp1       = scale + 1;
            var n         = x;
            var i         = DecimalX.Create(index);
            var im1       = DecimalX.Create(index - 1);
            var tolerance = DecimalX.Create(5);

            tolerance = tolerance.MovePointLeft(sp1);

            // The initial approximation is x/index.
            x = x.CDivide(i, scale, RoundingMode.HalfEven);

            // Loop until the approximations converge
            // (two successive approximations are equal after rounding).
            do
            {
                // x^(index-1)
                var xToIm1 = x.IntPower(index - 1, sp1);

                // x^index
                var xToI = x.Multiply(xToIm1);
                xToI = DecimalX.Rescale(xToI, -sp1, RoundingMode.HalfEven);

                // n + (index-1)*(x^index)
                var numerator = n.Add(im1.Multiply(xToI));
                numerator = DecimalX.Rescale(numerator, -sp1, RoundingMode.HalfEven);

                // (index*(x^(index-1))
                var denominator = i.Multiply(xToIm1);
                denominator = DecimalX.Rescale(denominator, -sp1, RoundingMode.HalfEven);

                // x = (n + (index-1)*(x^index)) / (index*(x^(index-1)))
                xPrev = x;
                x     = numerator.CDivide(denominator, sp1, RoundingMode.Down);
            } while (x.Subtract(xPrev).Abs().CompareTo(tolerance) > 0);

            return(x);
        }