/*
   ===========================================================================
   This function computes the arbitrary-precision exponential frunction.

   x = Argument as numeric string, like $x = '1.0123456789'
       so as not to be mistaken for a standard double-precision
       variable.

   ERRORS:
   FALSE is returned if non-numeric argument.

   NO DEPENDENCIES
   ===========================================================================
*/


   function BC_Exp ($xArgStr, $Decimals=16)
{
// Read (x) argument.
   $x = trim($xArgStr);

// -------------------------------------
// Error if (x) argument is non-numeric.

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

// -----------------------------------------------------
// Set internal working precision limit to 100 decimals.

   $Q = 100;

// ----------------------------------------------------------------
// Limit output decimals range from 1 to a maximum of 100 decimals.

   $q = trim($Decimals);  if ($q > 100){$q = 100;}  if ($q < 1) {$q = 1;}

   $flag = '';  if (bcComp($x, '-1', $Q) == 0) {$x = '1';  $flag = 'TRUE';}

// --------------------------
// Initial control variables.

   $denom = $numer = $prevSum = $CurrSum = '1';
   $prevSum =  $w =  '';

// -----------------------------
// Set decimals precision limit.

   $PrecisionLimit = '0.' . Str_Repeat('0', $q-1) . '1';

/* ---------------------------------------------------
   Perform summation loop and stop when set precision
   limit is reached or when (n == 100).
*/
   for ($n=1;   $n < 100;   $n++)
  {
   $numer   = bcMul($numer, $x, $Q);
   $denom   = bcMul($n, $denom);
   $term    = bcDiv($numer, $denom, $Q);
   $CurrSum = bcAdd($CurrSum, $term, $Q);
   $absDiff = Str_Replace('-', '', bcSub($CurrSum, $prevSum, $Q));

// -------------------------------------
// Stop when precision limit is reached.

   if (bcComp($absDiff, $PrecisionLimit, $Q) < 0) {break;}

// ---------------------------------------
// Replace previous sum value with current
// sum value for the next cycle, if any.

   $prevSum = $CurrSum;
  }

// -------------------------------------
// Account for special case of (x = -1).

   if ($flag) {$CurrSum = bcDiv('1', $CurrSum, $Q);}

// -------------------------------------------------
// Round off result to specified number of decimals.

   $CurrSum = trim(bcAdd($CurrSum, '0.'.Str_Repeat('0', $q).'5', $q));

// ------------------------------------------------
// Remove any redundant zeros and/or decimal point.

   return Rtrim(Rtrim($CurrSum, '0'), '.');

} // End of  BC_Exp()