////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001-2026 Alexey Kuryakin daqgroup@mail.ru under MIT license //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// This file is part of the CRW-DAQ project by DaqGroup - component CRWLIB.   //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Purpose:                                                                   //
// This unit implement LMath library functions.                               //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// History:                                                                   //
// 20260527 - Created by A.K.                                                 //
////////////////////////////////////////////////////////////////////////////////

unit _crw_lmath; //  Implement LMath library.

{$I _crw_sysdef.inc}

{$I _crw_sysmode.inc}

interface

uses
 //////////////////////////////////////////////////////
 {$I _crw_uses_first.inc} // NB: MUST BE FIRST USES !!!
 //////////////////////////////////////////////////////
 sysutils, classes, math,
 {$IFDEF USE_LMATH}utypes,{$ENDIF}
 _crw_alloc, _crw_fpu, _crw_ef, _crw_rtc, _crw_ee;

{$IFDEF USE_LMATH}
type
 TLMathWrapper = class(TMasterObject)
 public
  constructor Create;
  destructor  Destroy; override;
  procedure   AfterConstruction; override;
  procedure   BeforeDestruction; override;
  {
  lmGenMath
  }
 public
  {
  Sets the error code.
  }
  procedure SetErrCode(ErrCode : Integer; EMessage:string = '');
  {
  Sets error code and default function value.
  }
  function DefaultVal(ErrCode : Integer; DefVal : Float; EMessage:string = '') : Float;
  {
  Returns the error code.
  If user supplied ErrAddr for SetErrCode, it must be used here as well.
  }
  function MathErr : Integer;
  {
  Returns error message.
  }
  function MathErrMessage:string;
  {
  Compares to zero with epsilon set with SetZeroEpsilon.
  if SetZeroEpsilon was not set, MachEp / 8 is used.
  }
  function IsZero(F:Float): boolean;
  {
  Test if given vaule is NAN.
  }
  function IsNan(F : Float): Boolean;
  {
  Uses DefaultZeroEpsilon for test of equality with relative epsilon.
  DefaultZeroEpsilon may be set prior to call with SetEpsilon.
  Otherwise, it is MachEp.
  }
  function SameValue(A,B:Float):boolean;
  {
  Sets default epsilon for SameValue
  }
  function SetEpsilon(AEpsilon: float): Float;
  {
  Sets default epsilon for comparison of a number to zero
  (IsZero function) and to compare two numbers near zero.
  }
  function SetZeroEpsilon(AZeroEpsilon: Float):Float;
  {
  Rounds X to N decimal places
  }
  function RoundTo(X : Float; N : Integer) : Float;
  {
  Ceiling function
  }
  function Ceil(X : Float) : Integer;
  {
  Floor function
  }
  function Floor(X : Float) : Integer;
  {
  Pi = π
  }
  function  Pi          : Float; inline;
  {
  Euler's number (logarithm base)
  }
  function  Euler       : Float; inline;
  {
  Ln(2)
  }
  function  Ln2         : Float; inline;
  {
  Ln(10)
  }
  function  Ln10        : Float; inline;
  {
  Ln(Pi)
  }
  function  LnPi        : Float; inline;
  {
  1/Ln(2)
  }
  function  InvLn2      : Float; inline;
  {
  1/Ln(10)
  }
  function  InvLn10     : Float; inline;
  {
  2*Pi
  }
  function  TwoPi       : Float; inline;
  {
  Pi/2
  }
  function  PiDiv2      : Float; inline;
  {
  Sqrt(Pi)
  }
  function  SqrtPi      : Float; inline;
  {
  Sqrt(2*Pi)
  }
  function  Sqrt2Pi     : Float; inline;
  {
  1/Sqrt(2*Pi)
  }
  function  InvSqrt2Pi  : Float; inline;
  {
  Ln(Sqrt(2*Pi))
  }
  function  LnSqrt2Pi   : Float; inline;
  {
  Ln(2*Pi)/2
  }
  function  Ln2PiDiv2   : Float; inline;
  {
  Sqrt(2)
  }
  function  Sqrt2       : Float; inline;
  {
  Sqrt(2)/2
  }
  function  Sqrt2Div2   : Float; inline;
  {
  Golden Mean = (1 + Sqrt(5))/2
  }
  function  Gold        : Float; inline;
  {
  2 - GOLD
  }
  function  CGold       : Float; inline;
  {
  2^(-52)
  }
  function  MachEp      : Float; inline;
  {
  2^1024
  }
  function  MaxNum      : Float; inline;
  {
  2^(-1022)
  }
  function  MinNum      : Float; inline;
  function  MaxLog      : Float; inline;
  function  MinLog      : Float; inline;
  function  MaxFac      : Integer; inline;
  function  MaxGam      : Float; inline;
  function  MaxLgm      : Float; inline;
  function  NaN         : Float; inline;
  function  Infinity    : Float; inline;
  function  NegInfinity : Float; inline;
  {
  Exponential
  }
  function Expo(X : Float) : Float;
  {
  2^X
  }
  function Exp2(X : Float) : Float;
  {
  10^X
  }
  function Exp10(X : Float) : Float;
  {
  Natural log
  }
  function Log(X : Float) : Float;
  {
  Log, base 2
  }
  function Log2(X : Float) : Float;
  {
  Decimal log
  }
  function Log10(X : Float) : Float;
  {
  Log, base A
  }
  function LogA(X, A : Float) : Float;
  {
  X^N
  }
  function IntPower(X : Float; N : Integer) : Float;
  {
  X^Y, X >= 0
  }
  function Power(X, Y : Float) : Float;
  {
  Sign of Gamma function
  }
  function SgnGamma(X : Float) : Integer;
  {
  Stirling's formula for the Gamma function
  }
  function Stirling(X : Float) : Float;
  {
  Approximate Ln(Gamma) by Stirling's formula, for X >= 13
  }
  function StirLog(X : Float) : Float;
  {
  Gamma function
  }
  function Gamma(X : Float) : Float;
  {
  Logarithm of Gamma function
  }
  function LnGamma(X : Float) : Float;
  {
  Incomplete Gamma function
  }
  function IGamma(A, X : Float) : Float;
  {
  Complement of incomplete Gamma function
  }
  function JGamma(A, X : Float) : Float;
  {
  Error function
  }
  function Erf(X : Float) : Float;
  {
  Complement of error function
  }
  function Erfc(X : Float) : Float;
  {
  DiGamma(X : Float ) : Float;
  calculates the Digamma or Psi function = d ( LOG ( GAMMA ( X ) ) ) / dX
  Digamma calculates the Digamma or Psi function =   d ( LOG ( GAMMA ( X ) ) ) / dX
  Parameters:
  Input, real X, the argument of the Digamma function.
  0 < X.
  Output, real Digamma, the value of the Digamma function at X.
  }
  function DiGamma(X : Float ) : Float;
  {
  Trigamma calculates the Trigamma or Psi Prime function =
  d**2 ( LOG ( GAMMA ( X ) ) ) / dX**2
  }
  function TriGamma(X : Float ) : Float;
  {
  Computes Beta(X, Y) = Gamma(X) * Gamma(Y) / Gamma(X + Y)
  }
  function Beta(X, Y : Float) : Float; inline;
  {
  Incomplete Beta function
  }
  function IBeta(A, B, X : Float) : Float;
  {
  Lambert's W function: Y = W(X) ==> X = Y * Exp(Y)    X >= -1/e
    X       = Argument
    UBranch = TRUE  for computing the upper branch (X >= -1/e, W(X) >= -1)
              FALSE for computing the lower branch (-1/e <= X < 0, W(X) <= -1)
    Offset  = TRUE  for computing W(X - 1/e), X >= 0
              FALSE for computing W(X)
  }
  function LambertW(X : Float; UBranch, Offset : Boolean) : Float;
  {
  N!
  }
  function Fact(N : Integer) : Float;
  {
  Sqrt(X^2 + Y^2)
  }
  function Pythag(X, Y : Float) : Float;
  {
  Set Theta in -Pi..Pi
  }
  function FixAngle(Theta : Float) : Float;
  {
  Tangent
  }
  function Tan(X : Float) : Float;
  {
  Arc sinus
  }
  function ArcSin(X : Float) : Float;
  {
  Arc cosinus
  }
  function ArcCos(X : Float) : Float;
  {
  Angle (Ox, OM) with M(X,Y)
  }
  function ArcTan2(Y, X : Float) : Float;
  {
  Hyperbolic sine
  }
  function Sinh(X : Float) : Float;
  {
  Hyperbolic cosine
  }
  function Cosh(X : Float) : Float;
  {
  Hyperbolic tangent
  }
  function Tanh(X : Float) : Float;
  {
  Inverse hyperbolic sine
  }
  function ArcSinh(X : Float) : Float;
  {
  Inverse hyperbolic cosine
  }
  function ArcCosh(X : Float) : Float;
  {
  Inverse hyperbolic tangent
  }
  function ArcTanh(X : Float) : Float;
  {
  lmMathStat
  }
 public
  {
  Binomial coefficient C(N,K)
  }
  function Binomial(N, K : Integer) : Float;
  {
  Probability of binomial distribution
  }
  function PBinom(N : Integer; P : Float; K : Integer) : Float;
  {
  Density of exponential distribution with parameter A
  }
  function DExpo(A, X : Float) : Float;
  {
  Cumulative probability function for exponential dist. with parameter A
  }
  function FExpo(A, X : Float) : Float;
  {
  Given P, the function finds X such that IGamma(A, X) = P
  It is best valid in the right-hand tail of the distribution, P > 0.5
  }
  function InvGamma(A, P : Float) : Float;
  {
  Inverse of Khi-2 distribution function
  Returns the argument, X, for which the area under the Khi-2
  probability density function (integrated from 0 to X) is equal to P.
  }
  function InvKhi2(Nu : Integer; P : Float) : Float;
  {
  Density of Beta distribution with parameters A and B
  }
  function DBeta(A, B, X : Float) : Float;
  {
  Density of Gamma distribution with parameters A and B
  }
  function DGamma(A, B, X : Float) : Float;
  {
  Density of Khi-2 distribution with Nu d.o.f.
  }
  function DKhi2(Nu : Integer; X : Float) : Float;
  {
  Density of Student distribution with Nu d.o.f.
  }
  function DStudent(Nu : Integer; X : Float) : Float;
  {
  Density of Fisher-Snedecor distribution with Nu1 and Nu2 d.o.f.
  }
  function DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float;
  {
  Cumulative probability for Beta distrib. with param. A and B
  }
  function FBeta(A, B, X : Float) : Float;
  {
  Cumulative probability for binomial distrib.
  }
  function FBinom(N : Integer; P : Float; K : Integer) : Float;
  {
  Cumulative probability for Student distrib. with Nu d.o.f.
  }
  function FStudent(Nu : Integer; X : Float) : Float;
  {
  Prob(|t| > X) for Student distrib. with Nu d.o.f.
  }
  function PStudent(Nu : Integer; X : Float) : Float;
  {
  Cumulative prob. for Fisher-Snedecor distrib. with Nu1 and Nu2 d.o.f.
  }
  function FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float;
  {
  Prob(F > X) for Fisher-Snedecor distrib. with Nu1 and Nu2 d.o.f.
  }
  function PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float;
  {
  Cumulative probability for Gamma distrib. with param. A and B
  }
  function FGamma(A, B, X : Float) : Float;
  {
  Cumulative probability for Poisson distrib.
  }
  function FPoisson(Mu : Float; K : Integer) : Float;
  {
  Cumulative probability for standard normal distrib.
  }
  function FNorm(X : Float) : Float;
  {
  Prob(|U| > X) for standard normal distrib.
  }
  function PNorm(X : Float) : Float;
  {
  Cumulative prob. for khi-2 distrib. with Nu d.o.f.
  }
  function FKhi2(Nu : Integer; X : Float) : Float;
  {
  Prob(Khi2 > X) for khi-2 distrib. with Nu d.o.f.
  }
  function PKhi2(Nu : Integer; X : Float) : Float;
  {
  Inverse of incomplete Beta function.
  Given P, the function finds X such that IBeta(A, B, X) = Y
  }
  function InvBeta(A, B, Y : Float) : Float;
  {
  Inverse of Student's t-distribution function
  Given probability P, finds the argument X such that
  FStudent(Nu, X) = P
  }
  function InvStudent(Nu : Integer; P : Float) : Float;
  {
  Inverse of Snedecor's F-distribution function
  Given probability P, finds the argument X such that
  FSnedecor(Nu1, Nu2, X) = P
  }
  function InvSnedecor(Nu1, Nu2 : Integer; P : Float) : Float;
  {
  Inverse of Normal distribution function
  Returns the argument, X, for which the area under the Gaussian
  probability density function (integrated from minus infinity to X)
  is equal to P.
  }
  function InvNorm(P : Float) : Float;
  {
  Density of standard normal distribution
  }
  function DNorm(X : Float) : Float;
  {
  Density of gaussian distribution with orbitrary math. expectation and sigma
  }
  function DGaussian(X, Mean, Sigma: float) : float;
  {
  Probability of Poisson distrib.
  Probability to observe K if mean is mu
  }
  function PPoisson(Mu : Float; K : Integer) : Float;
  {
  Functions registration.
  }
 public
  function RegisterFunctions(ee:TExpressionEvaluator):Integer;
 end;

function LMath:TLMathWrapper;
{$ENDIF ~USE_LMATH}

function LMath_RegisterFunctions(ee:TExpressionEvaluator):Integer;

implementation

{$IFDEF USE_LMATH}
uses
 {lmGenMath}
 uerrors,umath,uround,ugamma,uigamma,udigamma,
 ubeta,uibeta,ulambert,ufact,utrigo,uhyper,
 {lmMathStat}
 ubinom,uexpdist,ugamdist,uibtdist,uigmdist,
 uinvbeta,uinvgam,uinvnorm,unormal,upoidist;

///////////////////////////////
// TLMathWrapper implementation
///////////////////////////////

constructor TLMathWrapper.Create;
begin
 inherited Create;
end;

destructor TLMathWrapper.Destroy;
begin
 inherited Destroy;
end;

procedure TLMathWrapper.AfterConstruction;
begin
 inherited AfterConstruction;
end;

procedure TLMathWrapper.BeforeDestruction;
begin
 inherited BeforeDestruction;
end;

procedure TLMathWrapper.SetErrCode(ErrCode : Integer; EMessage:string = '');
begin
 uerrors.SetErrCode(ErrCode, EMessage);
end;

function TLMathWrapper.DefaultVal(ErrCode : Integer; DefVal : Float; EMessage:string = '') : Float;
begin
 Result:=uerrors.DefaultVal(ErrCode, DefVal, EMessage);
end;

function TLMathWrapper.MathErr : Integer;
begin
 Result:=uerrors.MathErr;
end;

function TLMathWrapper.MathErrMessage:string;
begin
 Result:=uerrors.MathErrMessage;
end;

function TLMathWrapper.IsZero(F:Float): boolean;
begin
 Result:=utypes.IsZero(F);
end;

function TLMathWrapper.IsNan(F : Float): Boolean;
begin
 Result:=utypes.IsNan(F);
end;

function TLMathWrapper.SameValue(A,B:Float):boolean;
begin
 Result:=utypes.SameValue(A,B);
end;

function TLMathWrapper.SetEpsilon(AEpsilon: float):Float;
begin
 if (AEpsilon>0) then utypes.SetEpsilon(AEpsilon);
 Result:=utypes.DefaultEpsilon;
end;

function TLMathWrapper.SetZeroEpsilon(AZeroEpsilon: Float):Float;
begin
 if (AZeroEpsilon>0) then utypes.DefaultZeroEpsilon:=AZeroEpsilon;
 Result:=utypes.DefaultZeroEpsilon;
end;

function TLMathWrapper.RoundTo(X : Float; N : Integer) : Float;
begin
 Result:=uround.RoundTo(X, N);
end;

function TLMathWrapper.Ceil(X : Float) : Integer;
begin
 Result:=uround.Ceil(X);
end;

function TLMathWrapper.Floor(X : Float) : Integer;
begin
 Result:=uround.Floor(X);
end;

function  TLMathWrapper.Pi         : Float;
begin
 Result:=utypes.Pi;
end;

function  TLMathWrapper.Euler      : Float;
begin
 Result:=utypes.Euler;
end;

function  TLMathWrapper.Ln2        : Float;
begin
 Result:=utypes.Ln2;
end;

function  TLMathWrapper.Ln10       : Float;
begin
 Result:=utypes.Ln10;
end;

function  TLMathWrapper.LnPi       : Float;
begin
 Result:=utypes.LnPi;
end;

function  TLMathWrapper.InvLn2     : Float;
begin
 Result:=utypes.InvLn2;
end;

function  TLMathWrapper.InvLn10    : Float;
begin
 Result:=utypes.InvLn10;
end;

function  TLMathWrapper.TwoPi      : Float;
begin
 Result:=utypes.TwoPi;
end;

function  TLMathWrapper.PiDiv2     : Float;
begin
 Result:=utypes.PiDiv2;
end;

function  TLMathWrapper.SqrtPi     : Float;
begin
 Result:=utypes.SqrtPi;
end;

function  TLMathWrapper.Sqrt2Pi    : Float;
begin
 Result:=utypes.Sqrt2Pi;
end;

function  TLMathWrapper.InvSqrt2Pi : Float;
begin
 Result:=utypes.InvSqrt2Pi;
end;

function  TLMathWrapper.LnSqrt2Pi  : Float;
begin
 Result:=utypes.LnSqrt2Pi;
end;

function  TLMathWrapper.Ln2PiDiv2  : Float;
begin
 Result:=utypes.Ln2PiDiv2;
end;

function  TLMathWrapper.Sqrt2      : Float;
begin
 Result:=utypes.Sqrt2;
end;

function  TLMathWrapper.Sqrt2Div2  : Float;
begin
 Result:=utypes.Sqrt2Div2;
end;

function  TLMathWrapper.Gold       : Float;
begin
 Result:=utypes.Gold;
end;

function  TLMathWrapper.CGold      : Float;
begin
 Result:=utypes.CGold;
end;

function  TLMathWrapper.MachEp     : Float;
begin
 Result:=utypes.MachEp;
end;

function  TLMathWrapper.MaxNum     : Float;
begin
 Result:=utypes.MaxNum;
end;

function  TLMathWrapper.MinNum     : Float;
begin
 Result:=utypes.MinNum;
end;

function  TLMathWrapper.MaxLog     : Float;
begin
 Result:=utypes.MaxLog;
end;

function  TLMathWrapper.MinLog     : Float;
begin
 Result:=utypes.MinLog;
end;

function  TLMathWrapper.MaxFac     : Integer;
begin
 Result:=utypes.MaxFac;
end;

function  TLMathWrapper.MaxGam     : Float;
begin
 Result:=utypes.MaxGam;
end;

function  TLMathWrapper.MaxLgm     : Float;
begin
 Result:=utypes.MaxLgm;
end;

function  TLMathWrapper.NaN         : Float;
begin
 Result:=utypes.NaN;
end;

function  TLMathWrapper.Infinity    : Float;
begin
 Result:=utypes.Infinity;
end;

function  TLMathWrapper.NegInfinity : Float;
begin
 Result:=utypes.NegInfinity;
end;

function TLMathWrapper.Expo(X : Float) : Float;
begin
 Result:=umath.Expo(X);
end;

function TLMathWrapper.Exp2(X : Float) : Float;
begin
 Result:=umath.Exp2(X);
end;

function TLMathWrapper.Exp10(X : Float) : Float;
begin
 Result:=umath.Exp10(X);
end;

function TLMathWrapper.Log(X : Float) : Float;
begin
 Result:=umath.Log(X);
end;

function TLMathWrapper.Log2(X : Float) : Float;
begin
 Result:=umath.Log2(X);
end;

function TLMathWrapper.Log10(X : Float) : Float;
begin
 Result:=umath.Log10(X);
end;

function TLMathWrapper.LogA(X, A : Float) : Float;
begin
 Result:=umath.LogA(X, A);
end;

function TLMathWrapper.IntPower(X : Float; N : Integer) : Float;
begin
 Result:=umath.IntPower(X, N);
end;

function TLMathWrapper.Power(X, Y : Float) : Float;
begin
 Result:=umath.Power(X, Y);
end;

function TLMathWrapper.SgnGamma(X : Float) : Integer;
begin
 Result:=ugamma.SgnGamma(X);
end;

function TLMathWrapper.Stirling(X : Float) : Float;
begin
 Result:=ugamma.Stirling(X);
end;

function TLMathWrapper.StirLog(X : Float) : Float;
begin
 Result:=ugamma.StirLog(X);
end;

function TLMathWrapper.Gamma(X : Float) : Float;
begin
 Result:=ugamma.Gamma(X);
end;

function TLMathWrapper.LnGamma(X : Float) : Float;
begin
 Result:=ugamma.LnGamma(X);
end;

function TLMathWrapper.IGamma(A, X : Float) : Float;
begin
 Result:=uigamma.IGamma(A, X);
end;

function TLMathWrapper.JGamma(A, X : Float) : Float;
begin
 Result:=uigamma.JGamma(A, X);
end;

function TLMathWrapper.Erf(X : Float) : Float;
begin
 Result:=uigamma.Erf(X);
end;

function TLMathWrapper.Erfc(X : Float) : Float;
begin
 Result:=uigamma.Erfc(X);
end;

function TLMathWrapper.DiGamma(X : Float ) : Float;
begin
 Result:=udigamma.DiGamma(X);
end;

function TLMathWrapper.TriGamma(X : Float ) : Float;
begin
 Result:=udigamma.TriGamma(X);
end;

function TLMathWrapper.Beta(X, Y : Float) : Float;
begin
 Result:=ubeta.Beta(X,Y);
end;

function TLMathWrapper.IBeta(A, B, X : Float) : Float;
begin
 Result:=uibeta.IBeta(A, B, X);
end;

function TLMathWrapper.LambertW(X : Float; UBranch, Offset : Boolean) : Float;
begin
 Result:=ulambert.LambertW(X, UBranch, Offset);
end;

function TLMathWrapper.Fact(N : Integer) : Float;
begin
 Result:=ufact.Fact(N);
end;

function TLMathWrapper.Pythag(X, Y : Float) : Float;
begin
 Result:=utrigo.Pythag(X, Y);
end;

function TLMathWrapper.FixAngle(Theta : Float) : Float;
begin
 Result:=utrigo.FixAngle(Theta);
end;

function TLMathWrapper.Tan(X : Float) : Float;
begin
 Result:=utrigo.Tan(X);
end;

function TLMathWrapper.ArcSin(X : Float) : Float;
begin
 Result:=utrigo.ArcSin(X);
end;

function TLMathWrapper.ArcCos(X : Float) : Float;
begin
 Result:=utrigo.ArcCos(X);
end;

function TLMathWrapper.ArcTan2(Y, X : Float) : Float;
begin
 Result:=utrigo.ArcTan2(Y, X);
end;

function TLMathWrapper.Sinh(X : Float) : Float;
begin
 Result:=uhyper.Sinh(X);
end;

function TLMathWrapper.Cosh(X : Float) : Float;
begin
 Result:=uhyper.Cosh(X);
end;

function TLMathWrapper.Tanh(X : Float) : Float;
begin
 Result:=uhyper.Tanh(X);
end;

function TLMathWrapper.ArcSinh(X : Float) : Float;
begin
 Result:=uhyper.ArcSinh(X);
end;

function TLMathWrapper.ArcCosh(X : Float) : Float;
begin
 Result:=uhyper.ArcCosh(X);
end;

function TLMathWrapper.ArcTanh(X : Float) : Float;
begin
 Result:=uhyper.ArcTanh(X);
end;

function TLMathWrapper.Binomial(N, K : Integer) : Float;
begin
 Result:=ubinom.Binomial(N, K);
end;

function TLMathWrapper.PBinom(N : Integer; P : Float; K : Integer) : Float;
begin
 Result:=ubinom.PBinom(N, P, K);
end;

function TLMathWrapper.DExpo(A, X : Float) : Float;
begin
 Result:=uexpdist.DExpo(A, X);
end;

function TLMathWrapper.FExpo(A, X : Float) : Float;
begin
 Result:=uexpdist.FExpo(A, X);
end;

function TLMathWrapper.InvGamma(A, P : Float) : Float;
begin
 Result:=uinvgam.InvGamma(A, P);
end;

function TLMathWrapper.InvKhi2(Nu : Integer; P : Float) : Float;
begin
 Result:=uinvgam.InvKhi2(Nu, P);
end;

function TLMathWrapper.DBeta(A, B, X : Float) : Float;
begin
 Result:=ugamdist.DBeta(A, B, X);
end;

function TLMathWrapper.DGamma(A, B, X : Float) : Float;
begin
 Result:=ugamdist.DGamma(A, B, X);
end;

function TLMathWrapper.DKhi2(Nu : Integer; X : Float) : Float;
begin
 Result:=ugamdist.DKhi2(Nu, X);
end;

function TLMathWrapper.DStudent(Nu : Integer; X : Float) : Float;
begin
 Result:=ugamdist.DStudent(Nu, X);
end;

function TLMathWrapper.DSnedecor(Nu1, Nu2 : Integer; X : Float) : Float;
begin
 Result:=ugamdist.DSnedecor(Nu1, Nu2, X);
end;

function TLMathWrapper.FBeta(A, B, X : Float) : Float;
begin
 Result:=uibtdist.FBeta(A, B, X);
end;

function TLMathWrapper.FBinom(N : Integer; P : Float; K : Integer) : Float;
begin
 Result:=uibtdist.FBinom(N, P, K);
end;

function TLMathWrapper.FStudent(Nu : Integer; X : Float) : Float;
begin
 Result:=uibtdist.FStudent(Nu, X);
end;

function TLMathWrapper.PStudent(Nu : Integer; X : Float) : Float;
begin
 Result:=uibtdist.PStudent(Nu, X);
end;

function TLMathWrapper.FSnedecor(Nu1, Nu2 : Integer; X : Float) : Float;
begin
 Result:=uibtdist.FSnedecor(Nu1, Nu2, X);
end;

function TLMathWrapper.PSnedecor(Nu1, Nu2 : Integer; X : Float) : Float;
begin
 Result:=uibtdist.PSnedecor(Nu1, Nu2, X);
end;

function TLMathWrapper.FGamma(A, B, X : Float) : Float;
begin
 Result:=uigmdist.FGamma(A, B, X);
end;

function TLMathWrapper.FPoisson(Mu : Float; K : Integer) : Float;
begin
 Result:=uigmdist.FPoisson(Mu, K);
end;

function TLMathWrapper.FNorm(X : Float) : Float;
begin
 Result:=uigmdist.FNorm(X);
end;

function TLMathWrapper.PNorm(X : Float) : Float;
begin
 Result:=uigmdist.PNorm(X);
end;

function TLMathWrapper.FKhi2(Nu : Integer; X : Float) : Float;
begin
 Result:=uigmdist.FKhi2(Nu, X);
end;

function TLMathWrapper.PKhi2(Nu : Integer; X : Float) : Float;
begin
 Result:=uigmdist.PKhi2(Nu, X);
end;

function TLMathWrapper.InvBeta(A, B, Y : Float) : Float;
begin
 Result:=uinvbeta.InvBeta(A, B, Y);
end;

function TLMathWrapper.InvStudent(Nu : Integer; P : Float) : Float;
begin
 Result:=uinvbeta.InvStudent(Nu, P);
end;

function TLMathWrapper.InvSnedecor(Nu1, Nu2 : Integer; P : Float) : Float;
begin
 Result:=uinvbeta.InvSnedecor(Nu1, Nu2, P);
end;

function TLMathWrapper.InvNorm(P : Float) : Float;
begin
 Result:=uinvnorm.InvNorm(P);
end;

function TLMathWrapper.DNorm(X : Float) : Float;
begin
 Result:=unormal.DNorm(X);
end;

function TLMathWrapper.DGaussian(X, Mean, Sigma: float) : float;
begin
 Result:=unormal.DGaussian(X, Mean, Sigma);
end;

function TLMathWrapper.PPoisson(Mu : Float; K : Integer) : Float;
begin
 Result:=upoidist.PPoisson(Mu, K);
end;

////////////////////////////////////////
// ExpressionEvaluator binding functions
////////////////////////////////////////

function LMath_MathErr(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>0) then Exit(_NaN);
 Result:=LMath.MathErr;
end;

function LMath_SetErrCode(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 if (x[0]>=0) and not IsNan(x[0]) then LMath.SetErrCode(Round(x[0]));
 Result:=LMath.MathErr;
end;

function LMath_IsZero(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=BoolToInt(LMath.IsZero(x[0]));
end;

function LMath_IsNan(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=BoolToInt(LMath.IsNan(x[0]));
end;

function LMath_SameValue(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=BoolToInt(LMath.SameValue(x[0],x[1]));
end;

function LMath_SetEpsilon(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.SetEpsilon(x[0]);
end;

function LMath_SetZeroEpsilon(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.SetZeroEpsilon(x[0]);
end;

function LMath_RoundTo(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.RoundTo(x[0],Round(x[1]));
end;

function LMath_Ceil(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Ceil(x[0]);
end;

function LMath_Floor(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Floor(x[0]);
end;

function LMath_Expo(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Expo(x[0]);
end;

function LMath_Exp2(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Exp2(x[0]);
end;

function LMath_Exp10(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Exp10(x[0]);
end;

function LMath_Log(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Log(x[0]);
end;

function LMath_Log2(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Log2(x[0]);
end;

function LMath_Log10(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Log10(x[0]);
end;

function LMath_LogA(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.LogA(x[0], x[1]);
end;

function LMath_IntPower(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.IntPower(x[0], Round(x[1]));
end;

function LMath_Power(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.Power(x[0], x[1]);
end;

function LMath_SgnGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.SgnGamma(x[0]);
end;

function LMath_Stirling(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Stirling(x[0]);
end;

function LMath_StirLog(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.StirLog(x[0]);
end;

function LMath_Gamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Gamma(x[0]);
end;

function LMath_LnGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.LnGamma(x[0]);
end;

function LMath_IGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.IGamma(x[0], x[1]);
end;

function LMath_JGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.JGamma(x[0], x[1]);
end;

function LMath_Erf(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Erf(x[0]);
end;

function LMath_Erfc(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Erfc(x[0]);
end;

function LMath_DiGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.DiGamma(x[0]);
end;

function LMath_TriGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.TriGamma(x[0]);
end;

function LMath_Beta(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.Beta(x[0], x[1]);
end;

function LMath_IBeta(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.IBeta(x[0], x[1], x[2]);
end;

function LMath_LambertW(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.LambertW(x[0],(x[1]<>0),(x[2]<>0));
end;

function LMath_Fact(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
var N:Integer;
begin
 if (narg<>1) then Exit(_NaN);
 N:=Round(x[0]);
 if (N=x[0])
 then Result:=LMath.Fact(N)
 else Result:=LMath.Gamma(x[0]+1);
end;

function LMath_Pythag(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.Pythag(x[0],x[1]);
end;

function LMath_FixAngle(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.FixAngle(x[0]);
end;

function LMath_Tan(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Tan(x[0]);
end;

function LMath_ArcSin(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.ArcSin(x[0]);
end;

function LMath_ArcCos(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.ArcCos(x[0]);
end;

function LMath_ArcTan2(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.ArcTan2(x[0],x[1]);
end;

function LMath_Sinh(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Sinh(x[0]);
end;

function LMath_Cosh(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Cosh(x[0]);
end;

function LMath_Tanh(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.Tanh(x[0]);
end;

function LMath_ArcSinh(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.ArcSinh(x[0]);
end;

function LMath_ArcCosh(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.ArcCosh(x[0]);
end;

function LMath_ArcTanh(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.ArcTanh(x[0]);
end;

function LMath_Binomial(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.Binomial(Round(x[0]),Round(x[1]));
end;

function LMath_PBinom(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.PBinom(Round(x[0]),x[1],Round(x[2]));
end;

function LMath_DExpo(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.DExpo(x[0],x[1]);
end;

function LMath_FExpo(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.FExpo(x[0],x[1]);
end;

function LMath_InvGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.InvGamma(x[0],x[1]);
end;

function LMath_InvKhi2(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.InvKhi2(Round(x[0]),x[1]);
end;

function LMath_DBeta(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.DBeta(x[0],x[1],x[2]);
end;

function LMath_DGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.DGamma(x[0],x[1],x[2]);
end;

function LMath_DKhi2(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.DKhi2(Round(x[0]),x[1]);
end;

function LMath_DStudent(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.DStudent(Round(x[0]),x[1]);
end;

function LMath_DSnedecor(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.DSnedecor(Round(x[0]),Round(x[1]),x[2]);
end;

function LMath_FBeta(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.FBeta(x[0],x[1],x[2]);
end;

function LMath_FBinom(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.FBinom(Round(x[0]),x[1],Round(x[2]));
end;

function LMath_FStudent(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.FStudent(Round(x[0]),x[1]);
end;

function LMath_PStudent(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.PStudent(Round(x[0]),x[1]);
end;

function LMath_FSnedecor(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.FSnedecor(Round(x[0]),Round(x[1]),x[2]);
end;

function LMath_PSnedecor(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.PSnedecor(Round(x[0]),Round(x[1]),x[2]);
end;

function LMath_FGamma(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.FGamma(x[0],x[1],x[2]);
end;

function LMath_FPoisson(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.FPoisson(x[0],Round(x[1]));
end;

function LMath_FNorm(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.FNorm(x[0]);
end;

function LMath_PNorm(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.PNorm(x[0]);
end;

function LMath_FKhi2(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.FKhi2(Round(x[0]),x[1]);
end;

function LMath_PKhi2(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.PKhi2(Round(x[0]),x[1]);
end;

function LMath_InvBeta(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.InvBeta(x[0],x[1],x[2]);
end;

function LMath_InvStudent(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.InvStudent(Round(x[0]),x[1]);
end;

function LMath_InvSnedecor(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.InvSnedecor(Round(x[0]),Round(x[1]),x[2]);
end;

function LMath_InvNorm(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.InvNorm(x[0]);
end;

function LMath_DNorm(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>1) then Exit(_NaN);
 Result:=LMath.DNorm(x[0]);
end;

function LMath_DGaussian(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>3) then Exit(_NaN);
 Result:=LMath.DGaussian(x[0],x[1],x[2]);
end;

function LMath_PPoisson(ee:TExpressionEvaluator; const x:array of Double; narg:Integer):Double;
begin
 if (narg<>2) then Exit(_NaN);
 Result:=LMath.PPoisson(x[0],Round(x[1]));
end;

function TLMathWrapper.RegisterFunctions(ee:TExpressionEvaluator):Integer;
begin
 Result:=0;
 if Assigned(ee) then begin
  // Register Constants
  Result+=BoolToInt(ee.SetConst('LMath_Pi',            LMath.Pi             ));
  Result+=BoolToInt(ee.SetConst('LMath_Euler',         LMath.Euler          ));
  Result+=BoolToInt(ee.SetConst('LMath_Ln2',           LMath.Ln2            ));
  Result+=BoolToInt(ee.SetConst('LMath_Ln10',          LMath.Ln10           ));
  Result+=BoolToInt(ee.SetConst('LMath_LnPi',          LMath.LnPi           ));
  Result+=BoolToInt(ee.SetConst('LMath_InvLn2',        LMath.InvLn2         ));
  Result+=BoolToInt(ee.SetConst('LMath_InvLn10',       LMath.InvLn10        ));
  Result+=BoolToInt(ee.SetConst('LMath_TwoPi',         LMath.TwoPi          ));
  Result+=BoolToInt(ee.SetConst('LMath_PiDiv2',        LMath.PiDiv2         ));
  Result+=BoolToInt(ee.SetConst('LMath_SqrtPi',        LMath.SqrtPi         ));
  Result+=BoolToInt(ee.SetConst('LMath_Sqrt2Pi',       LMath.Sqrt2Pi        ));
  Result+=BoolToInt(ee.SetConst('LMath_InvSqrt2Pi',    LMath.InvSqrt2Pi     ));
  Result+=BoolToInt(ee.SetConst('LMath_LnSqrt2Pi',     LMath.LnSqrt2Pi      ));
  Result+=BoolToInt(ee.SetConst('LMath_Ln2PiDiv2',     LMath.Ln2PiDiv2      ));
  Result+=BoolToInt(ee.SetConst('LMath_Sqrt2',         LMath.Sqrt2          ));
  Result+=BoolToInt(ee.SetConst('LMath_Sqrt2Div2',     LMath.Sqrt2Div2      ));
  Result+=BoolToInt(ee.SetConst('LMath_Gold',          LMath.Gold           ));
  Result+=BoolToInt(ee.SetConst('LMath_CGold',         LMath.CGold          ));
  Result+=BoolToInt(ee.SetConst('LMath_MachEp',        LMath.MachEp         ));
  Result+=BoolToInt(ee.SetConst('LMath_MaxNum',        LMath.MaxNum         ));
  Result+=BoolToInt(ee.SetConst('LMath_MinNum',        LMath.MinNum         ));
  Result+=BoolToInt(ee.SetConst('LMath_MaxLog',        LMath.MaxLog         ));
  Result+=BoolToInt(ee.SetConst('LMath_MinLog',        LMath.MinLog         ));
  Result+=BoolToInt(ee.SetConst('LMath_MaxFac',        LMath.MaxFac         ));
  Result+=BoolToInt(ee.SetConst('LMath_MaxGam',        LMath.MaxGam         ));
  Result+=BoolToInt(ee.SetConst('LMath_MaxLgm',        LMath.MaxLgm         ));
  Result+=BoolToInt(ee.SetConst('LMath_NaN',           LMath.NaN            ));
  Result+=BoolToInt(ee.SetConst('LMath_Infinity',      LMath.Infinity       ));
  Result+=BoolToInt(ee.SetConst('LMath_NegInfinity',   LMath.NegInfinity    ));
  // Register Functions
  Result+=BoolToInt(ee.SetFunc('LMath_MathErr',        0, lmath_MathErr,        'LMath MathErr()'));
  Result+=BoolToInt(ee.SetFunc('LMath_SetErrCode',     1, lmath_SetErrCode,     'LMath SetErrCode(N)'));
  Result+=BoolToInt(ee.SetFunc('LMath_IsZero',         1, LMath_IsZero,         'LMath LMath_IsZero(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_IsNan',          1, LMath_IsNan,          'LMath LMath_IsNan(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_SameValue',      2, LMath_SameValue,      'LMath LMath_SameValue(A,B)'));
  Result+=BoolToInt(ee.SetFunc('LMath_SetEpsilon',     1, LMath_SetEpsilon,     'LMath LMath_SetEpsilon(E)'));
  Result+=BoolToInt(ee.SetFunc('LMath_SetZeroEpsilon', 1, LMath_SetZeroEpsilon, 'LMath LMath_SetZeroEpsilon(E)'));
  Result+=BoolToInt(ee.SetFunc('LMath_RoundTo',        2, LMath_RoundTo,        'LMath RoundTo(X,N)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Ceil',           1, LMath_Ceil,           'LMath Ceil(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Floor',          1, LMath_Floor,          'LMath Floor(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Expo',           1, LMath_Expo,           'LMath Expo(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Exp2',           1, LMath_Exp2,           'LMath Exp2(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Exp10',          1, LMath_Exp10,          'LMath Exp10(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Log',            1, LMath_Log,            'LMath Log(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Log2',           1, LMath_Log2,           'LMath Log2(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Log10',          1, LMath_Log10,          'LMath Log10(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_LogA',           2, LMath_LogA,           'LMath LogA(A,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_IntPower',       2, LMath_IntPower,       'LMath IntPower(X,N)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Power',          2, LMath_Power,          'LMath Power(X,Y)'));
  Result+=BoolToInt(ee.SetFunc('LMath_SgnGamma',       1, LMath_SgnGamma,       'LMath SgnGamma(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Stirling',       1, LMath_Stirling,       'LMath Stirling(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_StirLog',        1, LMath_StirLog,        'LMath StirLog(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Gamma',          1, LMath_Gamma,          'LMath Gamma(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_LnGamma',        1, LMath_LnGamma,        'LMath LnGamma(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_IGamma',         2, LMath_IGamma,         'LMath IGamma(A,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_JGamma',         2, LMath_JGamma,         'LMath JGamma(A,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Erf',            1, LMath_Erf,            'LMath Erf(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Erfc',           1, LMath_Erfc,           'LMath Erfc(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DiGamma',        1, LMath_DiGamma,        'LMath DiGamma(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_TriGamma',       1, LMath_TriGamma,       'LMath TriGamma(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Beta',           2, LMath_Beta,           'LMath Beta(X,Y)'));
  Result+=BoolToInt(ee.SetFunc('LMath_IBeta',          3, LMath_IBeta,          'LMath IBeta(A,B,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_LambertW',       3, lmath_LambertW,       'LMath LambertW(X,UBranch,Offset)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Fact',           1, lmath_Fact,           'LMath Fact(N)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Pythag',         2, LMath_Pythag,         'LMath Pythag(X,Y)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Hypot',          2, LMath_Pythag,         'LMath sqrt(X^2+Y^2)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FixAngle',       1, LMath_FixAngle,       'LMath FixAngle(Theta)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Tan',            1, LMath_Tan,            'LMath Tan(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_ArcSin',         1, LMath_ArcSin,         'LMath ArcSin(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_ArcCos',         1, LMath_ArcCos,         'LMath ArcCos(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_ArcTan2',        2, LMath_ArcTan2,        'LMath ArcTan2(Y,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Sinh',           1, LMath_Sinh,           'LMath Sinh(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Cosh',           1, LMath_Cosh,           'LMath Cosh(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Tanh',           1, LMath_Tanh,           'LMath Tanh(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_ArcSinh',        1, LMath_ArcSinh,        'LMath ArcSinh(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_ArcCosh',        1, LMath_ArcCosh,        'LMath ArcCosh(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_ArcTanh',        1, LMath_ArcTanh,        'LMath ArcTanh(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_Binomial',       2, LMath_Binomial,       'LMath Binomial(N,K)'));
  Result+=BoolToInt(ee.SetFunc('LMath_PBinom',         3, LMath_PBinom,         'LMath PBinom(N,P,K)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DExpo',          2, LMath_DExpo,          'LMath DExpo(A,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FExpo',          2, LMath_FExpo,          'LMath FExpo(A,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_InvGamma',       2, LMath_InvGamma,       'LMath InvGamma(A,P)'));
  Result+=BoolToInt(ee.SetFunc('LMath_InvKhi2',        2, LMath_InvKhi2,        'LMath InvKhi2(Nu,P)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DBeta',          3, LMath_DBeta,          'LMath DBeta(A,B,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DGamma',         3, LMath_DGamma,         'LMath DGamma(A,B,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DKhi2',          2, LMath_DKhi2,          'LMath DKhi2(Nu,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DStudent',       2, LMath_DStudent,       'LMath DStudent(Nu,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DSnedecor',      3, LMath_DSnedecor,      'LMath DSnedecor(Nu1,Nu2,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FBeta',          3, LMath_FBeta,          'LMath FBeta(A,B,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FBinom',         3, LMath_FBinom,         'LMath FBinom(N,P,K)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FStudent',       2, LMath_FStudent,       'LMath FStudent(Nu,K)'));
  Result+=BoolToInt(ee.SetFunc('LMath_PStudent',       2, LMath_PStudent,       'LMath PStudent(Nu,K)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FSnedecor',      3, LMath_FSnedecor,      'LMath FSnedecor(Nu1,Nu2,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_PSnedecor',      3, LMath_PSnedecor,      'LMath PSnedecor(Nu1,Nu2,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FGamma',         3, LMath_FGamma,         'LMath FGamma(A,B,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FPoisson',       2, LMath_FPoisson,       'LMath FPoisson(Mu,K)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FNorm',          1, LMath_FNorm,          'LMath FNorm(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_PNorm',          1, LMath_PNorm,          'LMath PNorm(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_FKhi2',          2, LMath_FKhi2,          'LMath FKhi2(Nu,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_PKhi2',          2, LMath_PKhi2,          'LMath PKhi2(Nu,X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_InvBeta',        3, LMath_InvBeta,        'LMath InvBeta(A,B,Y)'));
  Result+=BoolToInt(ee.SetFunc('LMath_InvStudent',     2, LMath_InvStudent,     'LMath InvStudent(Nu,P)'));
  Result+=BoolToInt(ee.SetFunc('LMath_InvSnedecor',    3, LMath_InvSnedecor,    'LMath InvSnedecor(Nu1,Nu2,P)'));
  Result+=BoolToInt(ee.SetFunc('LMath_InvNorm',        1, LMath_InvNorm,        'LMath InvNorm(P)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DNorm',          1, LMath_DNorm,          'LMath DNorm(X)'));
  Result+=BoolToInt(ee.SetFunc('LMath_DGaussian',      3, LMath_DGaussian,      'LMath DGaussian(X,Mean,Sigma)'));
  Result+=BoolToInt(ee.SetFunc('LMath_PPoisson',       2, LMath_PPoisson,       'LMath PPoisson(Mu,K)'));
 end;
end;

 ///////////////////////
 // LMath implementation
 ///////////////////////
function LMath:TLMathWrapper;
const LM:TLMathWrapper=nil;
begin
 if not Assigned(LM) then begin
  LM:=TLMathWrapper.Create;
  LM.Master:=@LM;
 end;
 Result:=LM;
end;
{$ENDIF ~USE_LMATH}

function LMath_RegisterFunctions(ee:TExpressionEvaluator):Integer;
begin
 {$IFDEF USE_LMATH}
 Result:=LMath.RegisterFunctions(ee);
 {$ELSE}
 Result:=0;
 {$ENDIF}
end;

///////////////////////////////////////
// Unit initialization and finalization
///////////////////////////////////////

procedure Init_crw_lmath;
begin
 {$IFDEF USE_LMATH}
 LMath.Ok;
 {$ENDIF}
end;

procedure Free_crw_lmath;
begin
 {$IFDEF USE_LMATH}
 LMath.Free;
 {$ENDIF}
end;

initialization

 Init_crw_lmath;

finalization

 Free_crw_lmath;

end.

//////////////
// END OF FILE
//////////////

