/// <summary> /// Compute the integral root of x to a given scale, x >= 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> < 0. /// </exception> /// <exception cref="ArgumentException"> /// if <c>self</c> < 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); }