Exemplo n.º 1
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);
        }
Exemplo n.º 2
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);
        }