MODULE  LOG3;   { Copyright (c) by  T. W. Lougheed   24 April 1981 }

{ This function returns the natural logarithm of the given
number with accuracy limited by machine precision.  It is much
more efficient than the algorithm used in PASCAL/MT 5.2  and just
as accurate, but could be improved, particularly in its Tchebyshev
polinimial.  For likely algorithms, see  COMPUTER APPROXIMATIONS
by John Hart & friends, 1978 by Krieger Pub. Co., Huntington NY. }

{ First version   5 February 1981

  By    T. W. Lougheed
        Dept. T. & A. Mechanics
        Thurston Hall, Cornell U.
        Ithaca,  NY  14853

  Last version  23 February 1981

  This software is in the public domain, and may not be sold by any
  person or corperation without permission of the author.  }


FUNCTION  LN( Z :REAL ) :REAL;

CONST   { If the input is zero or negative, the output is
        - maxreal. }

        MAXREAL = 9.9999E17;

VAR     LOGARITHM : REAL;


{ This procedure reduces the exponent of Z to 1 and
sets  LOGARITHM  to the value of the removed part.
  Note that this must be re-written for every new
internal representation of the reals. }


PROCEDURE  MANGLE_Z;

   CONST   { The following are used for the conversion of the
           exponential part of  Z  directly to a logarithm. }

           LOG_2 = 0.6931471805994531;

           EXPT_MASK = $7F;  { Exponent is a power of  2  stored in bits
                             six through zero in two-s complement format. }

           EXPT_SIGN_BIT = 6;  { Bit to test to get sign of exponent. }

   VAR  EXPONENT :BYTE;

   BEGIN


   MOVE( Z, EXPONENT, 1 );

   { The exponent is in a two's compement form:  all negative
   numbers are of the form  128 - V  where  V  is the absolute
   value of the negative part, hence subtract 128 to get negative
   number.  Bit 7 is the sign of the characteristic. }
   IF TSTBIT( EXPONENT, EXPT_SIGN_BIT )
      THEN LOGARITHM := LOG_2*(ORD( EXPONENT&EXPT_MASK ) - 129)
      ELSE LOGARITHM := LOG_2*(ORD( EXPONENT&EXPT_MASK ) - 1);

   { Make the number  Z  to be between  1  and  2. }
   EXPONENT := CHR( 1 );
   MOVE( EXPONENT, Z, 1 );
   END;



   { This function is a Tchebyshev polinomial for the natural
   logarithm of one plus its argument.  The formula is from
   THE HANDBOOK OF MATHEMATICAL FUNCTIONS  (10-th printing)
   by Abramowicz and Stegun, formula  4.1.44.  The error is
   less than  3E-8  for argument  X  between  0 and 1 inclusive. }

   FUNCTION  TCHEBYSHEV( X :REAL) :REAL;

   CONST  A1 =  0.9999964239;
          A2 = -0.4998741238;
          A3 =  0.3317990258;
          A4 = -0.2407338048;
          A5 =  0.1676540711;
          A6 = -0.0953293879;
          A7 =  0.0360884937;
          A8 = -0.0064535442;

   BEGIN
   TCHEBYSHEV := (((((((A8*X + A7)*X + A6)*X + A5)*X + A4)*X +
    A3)*X + A2)*X + A1)*X;
   { TCHEBYSHEV = LN( 1 + X ). }
   END;



BEGIN
IF Z <= 0 THEN LN := - MAXREAL
   ELSE BEGIN
   MANGLE_Z;
   LN := LOGARITHM + TCHEBYSHEV( Z - 1 );
   END;
END;

MODEND
.
