/*
   ###########################################################################
   This function computes the arbitrary-precision Nth root of a given any
   numerical string X, rounded to any specified number of decimals.

   ----------
   ARGUMENTS:
   N = Root to be iterated = Integer 1, 2, 3, 4, ..., etc.
   X = Numerical string for which we seek the Nth root.

   Decimals = Number of decimals at which to round off the result
              if exact resolution is not possible.

   Based on the following Nth root of X iteration algorithm.

   -----------------------
   Nth ROOT of X ITERATION

   Let:
   N = Root to be iterated (2=Square root, 3=Cube root, etc.)

   a = current approximation to Nth root of (X)
       Initial approximation = Normal native machine precision value

   b = next generation approximation computed from current (a)

   p = Precision limit.
       10^(-(decimals + 1))
       If we want 16 decimals of
       precision, then we set:
       p = 10^(-(16 + 1))
         = 10^(-17)
         = 10E-17
         = 0.00000000000000001

   At the end of each iteration, the resulting value of (b) becomes the
   new value of (a) for the next cycle and the process is repeated until
   the desired precision level is reached.

   The iteration process continues while (abs(b-a) >= p)

   When the difference abs(b-a) < p, then we are
   done and the current value of (b) is returned.

   ---------------------------------
   Nth ROOT of X ITERATION ALGORITHM

   GIVEN (N, X, a, Decimals)

   START
   c = 1
   n = N - 1
   p = 10^(-(Decimals + 1))

   LOOP_WHILE (c >= p)
  {
   b = (a + X/(a^n)) / n
   c = abs(b - a)
   a = b
  }
   return b
   end


   ERRORS:
   FALSE is returned if either (N, X) argument is non-numeric .

   NO DEPENDENCIES
   ###########################################################################
*/

   function BC_Nth_Root ($N, $X, $Decimals=16)
{
   $x = trim($X);
   $N = trim($N);

   if (!Is_Numeric($x) or !Is_Numeric($N))
  {
   return FALSE;
  }

   $N = floor(abs($N));

// Check for odd root value with negative argument, in which
// case, the sign of the argument is preserved in the root.

   $sign = '';  if ($x < 0) {$x = Str_Replace('-', '', $x);  $sign = '-';}

// --------------------------------------------------
// Generate 1st approximation = Native machine value.

   $a = SPrintF("%1.16f", pow($x, 1/$N));
   $n = floor(abs($N)) - 1;
   $d = floor(abs($Decimals));
   $D = 2*$d;

/* ---------------------------------------------------
   Loop to iterate root value (limit = 50 iterations).
   This should never get anywhere near 50.  This limit
   prevents a total lockup if something goes wrong.
*/
   for ($i=1;  $i <= 50;   $i++)
  {
// --------------------------------------------------------------
// Compute next approximation (b) from current approximation (a).

   $b = bcDiv(bcAdd(bcMul($n,$a,$D),bcDiv($x,bcpow($a,$n,$D),$D),$D),$N,$D);

/* ------------------------------------------
   If (a == b) to precision limit, then done.
   Otherwise, execute another loop cycle.
*/
   if (bcComp($a,$b,$D) == 0) {break;} else {$a = $b;}
  }
// Done.  Return root value rounded to specified number of decimals.

   $w = $sign.bcAdd($b, '0.'.Str_Repeat(0,$d).'5', $d);

   if ($w == bcAdd('0', $w))
      {
       $w = Rtrim(Rtrim($w, '0'), '.');
      }

   return $w;

} // End of  BC_Nth_Root (...)