Ejemplo n.º 1
0
        private static DecimalX expTaylor(DecimalX x, int scale)
        {
            DecimalX sumPrev;

            var factorial = DecimalX.Create(1);
            var xPower    = x;

            // 1 + x
            var sum = x.Add(DecimalX.Create(1));

            // Loop until the sums converge
            // (two successive sums are equal after rounding).
            var i = 2;

            do
            {
                // x^i
                xPower = xPower.Multiply(x);
                xPower = DecimalX.Rescale(xPower, -scale, RoundingMode.HalfEven);

                // i!
                factorial = factorial.Multiply(DecimalX.Create(i));

                // x^i/i!
                var term = xPower.CDivide(factorial, scale, RoundingMode.HalfEven);

                // sum = sum + x^i/i!
                sumPrev = sum;
                sum     = sum.Add(term);

                i++;
            } while (sum.CompareTo(sumPrev) != 0);

            return(sum);
        }
Ejemplo n.º 2
0
        public void LnTest()
        {
            var dec1 = DecimalX.Create("2.65");
            var s    = dec1.Ln(32).ToString();

            Assert.IsTrue(s == "0.97455963999813084070924556288652");
        }
Ejemplo n.º 3
0
        public void IntRootTest()
        {
            var dec1 = DecimalX.Create("4.2345");
            var s    = dec1.IntRoot(2, 30).ToString();

            Assert.IsTrue(s == "2.0577900767571020629770974914148");
        }
Ejemplo n.º 4
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);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Compute x^exponent to a given scale. Uses the same algorithm as class
        /// numbercruncher.mathutils.IntPower.
        /// </summary>
        /// <param name="exponent">
        /// the exponent 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>
        public static DecimalX IntPower(this DecimalX x, long exponent, int scale)
        {
            if (scale < 0)
            {
                throw new ArgumentException(InvalidScale);
            }

            if (exponent < 0)
            {
                var a = DecimalX.Create(1);
                return(a.CDivide(x.IntPower(-exponent, scale), scale, RoundingMode.HalfEven));
            }

            var power = DecimalX.Create(1);

            while (exponent > 0)
            {
                if ((exponent & 1) == 1)
                {
                    power = power.Multiply(x);
                    power = DecimalX.Rescale(power, -scale, RoundingMode.HalfEven);
                }

                x        = x.Multiply(x);
                x        = DecimalX.Rescale(x, -scale, RoundingMode.HalfEven);
                exponent = exponent >> 1;
            }

            return(power);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Compute the natural logarithm of x to a given scale, x > 0.
        /// </summary>
        public static DecimalX Ln(this DecimalX x, int scale)
        {
            // Check that scale > 0.
            if (scale <= 0)
            {
                throw new ArgumentException(InvalidScale2);
            }

            // Check that x > 0.
            if (x.Signum() <= 0)
            {
                throw new ArgumentException(NegativeOrZeroNaturalLog);
            }

            // The number of digits to the left of the decimal point.
            var magnitude = x.ToString().Length - -x.Exponent - 1;

            if (magnitude < 3)
            {
                return(lnNewton(x, scale));
            }

            // x^(1/magnitude)
            var root = x.IntRoot(magnitude, scale);

            // ln(x^(1/magnitude))
            var lnRoot = lnNewton(root, scale);

            // magnitude*ln(x^(1/magnitude))
            var a      = DecimalX.Create(magnitude);
            var result = a.Multiply(lnRoot);

            return(DecimalX.Rescale(result, -scale, RoundingMode.HalfEven));
        }
Ejemplo n.º 7
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));
        }
Ejemplo n.º 8
0
        public void ExpTest()
        {
            DecimalX dec1;
            string   s;

            dec1 = DecimalX.Create("1");
            s    = dec1.Exp(46).ToString();
            Assert.IsTrue(s == "2.7182818284590452353602874713526624977572470937");
            dec1 = DecimalX.Create("-0.5");
            s    = dec1.Exp(32).ToString();
            Assert.IsTrue(s == "0.60653065971263342360379953499118");
        }
Ejemplo n.º 9
0
        private static DecimalX CDivide(this DecimalX dividend, DecimalX divisor, int scale, RoundingMode roundingMode)
        {
            if (dividend.CheckExponent((long)scale + -divisor.Exponent) > -dividend.Exponent)
            {
                dividend = DecimalX.Rescale(dividend, -scale + divisor.Exponent, RoundingMode.Unnecessary);
            }
            else
            {
                divisor = DecimalX.Rescale(divisor, dividend.CheckExponent((long)dividend.Exponent - -scale), RoundingMode.Unnecessary);
            }

            return(new DecimalX(DecimalX.RoundingDivide2(dividend.Coefficient, divisor.Coefficient, roundingMode), -scale));
        }
Ejemplo n.º 10
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);
        }
Ejemplo n.º 11
0
        public void SqrtTest()
        {
            DecimalX dec1;
            string   s;

            dec1 = DecimalX.Create(16);
            s    = dec1.Sqrt(1).ToString();
            Assert.IsTrue(s == "4.0");

            dec1 = DecimalX.Create("0.0");
            s    = dec1.Sqrt(2).ToString();
            Assert.IsTrue(s == "0.00");

            dec1 = DecimalX.Create("2.0");
            s    = dec1.Sqrt(200).ToString();
            Assert.IsTrue
                (s == "1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206057147");

            dec1 = DecimalX.Create("25.0");
            s    = dec1.Sqrt(4).ToString();
            Assert.IsTrue(s == "5.0000");

            dec1 = DecimalX.Create("1.000");
            s    = dec1.Sqrt(1).ToString();
            Assert.IsTrue(s == "1.0");

            dec1 = DecimalX.Create(6);
            s    = dec1.Sqrt(4).ToString();
            Assert.IsTrue(s == "2.4494");

            dec1 = DecimalX.Create("0.5");
            s    = dec1.Sqrt(6).ToString();
            Assert.IsTrue(s == "0.707106");

            dec1 = DecimalX.Create("5113.51315");
            s    = dec1.Sqrt(4).ToString();
            Assert.IsTrue(s == "71.5088");

            dec1 = DecimalX.Create("15112345");
            s    = dec1.Sqrt(6).ToString();
            Assert.IsTrue(s == "3887.459967");

            dec1 = DecimalX.Create("783648276815623658365871365876257862874628734627835648726");
            s    = dec1.Sqrt(58).ToString();
            Assert.IsTrue(s == "27993718524262253829858552106.4622387227347572406137833208384678543897305217402364794553");
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Compute the square root of self to a given scale, Using Newton's
        /// algorithm. x &gt;= 0.
        /// </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> is &lt;= 0.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// if <c>self</c> is &lt; 0.
        /// </exception>
        public static DecimalX Sqrt(this DecimalX x, int scale)
        {
            // Check that scale > 0.
            if (scale <= 0)
            {
                throw new ArgumentException(SqrtScaleInvalid);
            }

            // Check that x >= 0.
            if (x.Signum() < 0)
            {
                throw new ArgumentException(NegativeSquareRoot);
            }

            if (x.Signum() == 0)
            {
                return(new DecimalX(x.ToIntegerX(), -scale));
            }

            // n = x*(10^(2*scale))
            var n = x.MovePointRight(scale << 1).ToIntegerX();

            // The first approximation is the upper half of n.
            var      bits   = (int)(n.BitLength() + 1) >> 1;
            var      ix     = n.RightShift(bits);
            IntegerX ixPrev = 0;

            // Loop until the approximations converge
            // (two successive approximations are equal after rounding).
            while (ix.CompareTo(ixPrev) != 0)
            {
                ixPrev = ix;

                // x = (x + n/x)/2
                ix = ix.Add(n.Divide(ix)).RightShift(1);
            }

            return(new DecimalX(ix, -scale));
        }