%mathpiper,def="N;NonN;InNumericMode"

//"+-;/-;*-;^-;:=-;:=+" These were in the def list.

/* See the documentation on the assignment of the precedence of the rules.
 */

/* Some very basic functions that are used always any way... */

/* Implementation of numeric mode */

//Retract("N",*);

LocalSymbols(numericMode)
[

  numericMode := False;

  // N function: evaluate numerically with given precision.
  LocalSymbols(previousNumericMode, previousPrecision, numericResult) 
  Macro("N",{expression, precision})
  [
    //If(InVerboseMode(),
    //    [Tell("N",{expression,precision}); Tell("  ",{@expression,@precision});]
    //);
    
    // we were in non-numeric mode
    Local(previousNumericMode, previousPrecision, numericResult, exception);

    previousPrecision := BuiltinPrecisionGet();
    //If(InVerboseMode(),Tell("  ",previousPrecision));
    BuiltinPrecisionSet(@precision+5);

    AssignCachedConstantsN();

    previousNumericMode := numericMode;
    numericMode         := True;
    exception         := False;

    //ExceptionCatch(Bind(numericResult, Eval(@expression)),Bind(exception,ExceptionGet()));

    ExceptionCatch( numericResult:=Eval(@expression), exception := ExceptionGet() );
    //If(InVerboseMode(),Tell("  1",numericResult));

    If(IsDecimal(numericResult), numericResult := RoundToN(numericResult, @precision));
    //If(InVerboseMode(),Tell("  2",numericResult));

    numericMode := previousNumericMode;

    If(Not numericMode, [ ClearCachedConstantsN(); ] );

    BuiltinPrecisionSet(previousPrecision);

    Check(exception = False, exception["type"], exception["message"]);

    numericResult;

  ];




  // N function: evaluate numerically with default precision.
  LocalSymbols(precision,heldExpression) 
  Macro("N",{expression})
  [
     Local(precision, heldExpression);
     precision      :=  BuiltinPrecisionGet();
     heldExpression :=  Hold(@expression);

     `N(@heldExpression, @precision);
  ];

  
  // NoN function.
  LocalSymbols(result) 
  Macro("NonN",{expression})
  [
    Local(result);
    GlobalPush(numericMode);
    numericMode := False;
    result      := (@expression);
    numericMode := GlobalPop();
    result;
  ];


  // InNumericMode function.
  Function("InNumericMode",{}) numericMode;

]; //LocalSymbols(numericMode)

%/mathpiper

    %output,preserve="false"
      Result: True
.   %/output

   





%mathpiper_docs,name="N",categories="User Functions;Numbers (Operations)"
*CMD N --- try to determine an numerical approximation of expression

*CALL
	N(expression)
	N(expression, precision)
*PARMS

{expression} -- expression to evaluate

{precision} -- integer, precision to use

*DESC

The function {N} instructs {MathPiper} to try to coerce an expression in to a numerical approximation to the
expression {expr}, using {prec} digits precision if the second calling
sequence is used, and the default precision otherwise. This overrides the normal
behaviour, in which expressions are kept in symbolic form (eg. {Sqrt(2)} instead of {1.41421}).

Application of the {N} operator will make MathPiper
calculate floating point representations of functions whenever
possible. In addition, the variable {Pi} is bound to
the value of $Pi$ calculated at the current precision.
(This value is a "cached constant", so it is not recalculated each time {N} is used, unless the precision is increased.)


{N} is a macro. Its argument {expr} will only
be evaluated after switching to numeric mode.

*E.G.
In> 1/2
Result: 1/2;
In> N(1/2)
Result: 0.5;
In> Sin(1)
Result: Sin(1);
In> N(Sin(1),10)
Result: 0.8414709848;
In> Pi
Result: Pi;
In> N(Pi,20)
Result: 3.1415926535897932385

*SEE Pi, InNumericMode, NonN
%/mathpiper_docs

    %output,preserve="false"
      
.   %/output




%mathpiper_docs,name="InNumericMode",categories="User Functions;Predicates"
*CMD InNumericMode --- determine if currently in numeric mode

*CALL
	InNumericMode()

*DESC

When in numeric mode, {InNumericMode()} will return {True}, else it will
return {False}. {MathPiper} is in numeric mode when evaluating an expression
with the function {N}. Thus when calling {N(expr)}, {InNumericMode()} will
return {True} while {expr} is being evaluated.

{InNumericMode()} would typically be used to define a transformation rule
that defines how to get a numeric approximation of some expression. One
could define a transformation rule

	f(_x)_InNumericMode() <- [... some code to get a numeric approximation of f(x) ... ];

{InNumericMode()} usually returns {False}, so transformation rules that check for this
predicate are usually left alone.


*E.G.
In> InNumericMode()
Result: False
In> N(InNumericMode())
Result: True

*SEE N, BuiltinPrecisionSet, BuiltinPrecisionGet, Pi, CachedConstant
%/mathpiper_docs





%mathpiper_docs,name="NonN",categories="User Functions;Numbers (Operations)"
*CMD NonN --- calculate part in non-numeric mode

*CALL
	NonN(expr)

*PARMS
{expr} -- expression to evaluate

*DESC
When in numeric mode, {NonN} can be called to switch back to non-numeric
mode temporarily.

{NonN} is a macro. Its argument {expr} will only
be evaluated after the numeric mode has been set appropriately.

*E.G.
In> N(NonN(InNumericMode()))
Result: False

*SEE N, BuiltinPrecisionSet, BuiltinPrecisionGet, Pi, CachedConstant
%/mathpiper_docs
