%mathpiper,def=""

//todo:tk:this MathPI cannot be in a def file because it conflicts with the MathPI in base.rep/elemfunctions.

/** This file contains routines for numerical evaluation of elementary functions:
 *  PowerN, ExpN, SinN etc.
 *  It is assumed that the arguments are real (not complex) floating-point or integer numbers. (The {InNumericMode()} flag does not have to be set.)
 *  The result is an exact integer or a floating-point number correct to BuiltinPrecisionGet() digits.
 *
 *  If a better optimized version of these functions is available through the kernel,
 *  then the kernel version will automatically shadow these functions.
 *  These implementations are not necessarily the best optimized versions.
 */

/// The constant Pi. Using a simple method, solve Cos(x)=0.
// iterate x := x + Cos(x) + 1/6 *Cos(x)^3 + ... to converge to x=Pi/2
MathPi() :=
[
	Local(result, delta, deltasq, k, order, prec, curprec);
	order := 13;	// order of approximation
	prec := BuiltinPrecisionGet();
  N([
    /* initial approximation */
    curprec := 20;
    BuiltinPrecisionSet(curprec);
    result := 3.14159265358979323846*0.5;
    // find optimal initial precision
    For(k:=prec, k>=curprec, k:=Quotient(k,order)+2) True;
    If(k<5, curprec:=5, curprec:=k);
  //	Echo("initial precision", curprec);
    // now k is the iteration counter
    For(k:=0, curprec < prec, k := k+1) [
    // at this iteration we know the result to curprec digits
      curprec := Minimum(prec, curprec * order-2);	// 2 guard digits
      BuiltinPrecisionSet(curprec+2);
  //		Echo("Iteration ", k, " setting precision to ", BuiltinPrecisionGet());
  //		Echo("old result=", CosN(result));
      /*EchoTime()*/[
      delta := CosN(result);
      ];
      /*EchoTime()*/[
      deltasq := MultiplyN(delta,delta);
      ];
      result := /*EchoTime()*/result + delta*(1 + deltasq*(1/6 + deltasq*(3/40 + deltasq*(5/112 + deltasq*(35/1152 + (deltasq*63)/2816)))));
    ];
  //	Echo({"Method 3, using Pi/2 and order", order, ":", k, "iterations"});
  ]);
	result*2;
];

%/mathpiper







%mathpiper_docs,name="MathPi",categories="User Functions;Numeric",access="experimental"
*CMD MathPi --- The constant Pi.
*CALL
	MathPi()

*DESC

The constant Pi. Using a simple method, solve Cos(x)=0.
iterate x := x + Cos(x) + 1/6 *Cos(x)^3 + ... to converge to x=Pi/2

It is assumed that the arguments are real (not complex) floating-point or integer numbers. (The {InNumericMode()} flag does not have to be set.)
The result is an exact integer or a floating-point number correct to BuiltinPrecisionGet() digits.

If a better optimized version of this function is available through the kernel,
then the kernel version will automatically shadow this function.
This implementation is not necessarily the best optimized version.


%/mathpiper_docs