' ******************************************************************
' Mathematical functions (logarithms and exponentials)
' ******************************************************************

' ------------------------------------------------------------------
' Error codes
' ------------------------------------------------------------------

#DEFINE FOk 0  
' No error

#DEFINE FDomain -1  
' Argument domain error

#DEFINE FSing -2  
' Singularity

#DEFINE FOverflow -3  
' Overflow range error

#DEFINE FUnderflow -4  
' Underflow range error

' ------------------------------------------------------------------
' Machine-dependent constants
' ------------------------------------------------------------------

#DEFINE MaxNum 1.797693134862315D+308   
' Max. floating point number: 2^1024

#DEFINE MaxLog 709.782712893384#        
' Max. argument for Exp

#DEFINE MinLog -708.3964185322641#       
' Min. argument for Exp

' ------------------------------------------------------------------
' Mathematical constants
' ------------------------------------------------------------------

#DEFINE Ln2 0.6931471805599453#  
' Ln(2)

#DEFINE Ln10 2.302585092994046#   
' Ln(10)

#DEFINE InvLn2 1.442695040888963#   
' 1/Ln(2)

#DEFINE InvLn10 0.4342944819032518#  
' 1/Ln(10)

' ------------------------------------------------------------------
' Global variable
' ------------------------------------------------------------------

COMMON SHARED ErrCode AS INTEGER
' Error code from the latest function evaluation

' ******************************************************************

FUNCTION Exp10 (X AS DOUBLE) AS DOUBLE
  DIM XLn10 AS DOUBLE
   
  XLn10 = X * Ln10
  IF XLn10 < MinLog THEN
    ErrCode = FUnderflow
    Exp10 = 0
  ELSEIF XLn10 > MaxLog THEN
    ErrCode = FOverflow
    Exp10 = MaxNum
  ELSE
    ErrCode = FOk
    Exp10 = EXP(XLn10)
  END IF
END FUNCTION

FUNCTION Exp2 (X AS DOUBLE) AS DOUBLE
  DIM XLn2 AS DOUBLE
 
  XLn2 = X * Ln2
  IF XLn2 < MinLog THEN
    ErrCode = FUnderflow
    Exp2 = 0
  ELSEIF XLn2 > MaxLog THEN
    ErrCode = FOverflow
    Exp2 = MaxNum
  ELSE
    ErrCode = FOk
    Exp2 = EXP(XLn2)
  END IF
END FUNCTION

FUNCTION Expo (X AS DOUBLE) AS DOUBLE
  IF X < MinLog THEN
    ErrCode = FUnderflow
    Expo = 0
  ELSEIF X > MaxLog THEN
    ErrCode = FOverflow
    Expo = MaxNum
  ELSE
    ErrCode = FOk
    Expo = EXP(X)
  END IF
END FUNCTION

FUNCTION Ln (X AS DOUBLE) AS DOUBLE
  IF X < 0 THEN
    ErrCode = FDomain
    Ln = -MaxNum
  ELSEIF X = 0 THEN
    ErrCode = FSing
    Ln = -MaxNum
  ELSE
    ErrCode = FOk
    Ln = LOG(X)
  END IF
END FUNCTION

FUNCTION Log10 (X AS DOUBLE) AS DOUBLE
  IF X < 0 THEN
    ErrCode = FDomain
    Log10 = -MaxNum
  ELSEIF X = 0 THEN
    ErrCode = FSing
    Log10 = -MaxNum
  ELSE
    ErrCode = FOk
    Log10 = LOG(X) * InvLn10
  END IF
END FUNCTION

FUNCTION Log2 (X AS DOUBLE) AS DOUBLE
  IF X < 0 THEN
    ErrCode = FDomain
    Log2 = -MaxNum
  ELSEIF X = 0 THEN
    ErrCode = FSing
    Log2 = -MaxNum
  ELSE
    ErrCode = FOk
    Log2 = LOG(X) * InvLn2
  END IF
END FUNCTION

FUNCTION LogA (X AS DOUBLE, A AS DOUBLE) AS DOUBLE
  DIM Y AS DOUBLE
 
  Y = Ln(X)
  IF ErrCode = FOk THEN
    IF A = 1 THEN
      ErrCode = FSing
      Y = SGN(Y) * MaxNum
    ELSE
      Y = Y / Ln(A)
    END IF
    LogA = Y
  END IF
END FUNCTION

