455 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			455 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
(*
 | 
						|
  (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
  See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
*)
 | 
						|
 | 
						|
(*$R-*)
 | 
						|
IMPLEMENTATION MODULE Mathlib;
 | 
						|
(*
 | 
						|
  Module:	Mathematical functions
 | 
						|
  Author:	Ceriel J.H. Jacobs
 | 
						|
  Version:	$Header$
 | 
						|
*)
 | 
						|
 | 
						|
  FROM EM IMPORT FIF, FEF;
 | 
						|
  FROM Traps IMPORT Message;
 | 
						|
 | 
						|
	(* From:	Handbook of Mathematical Functions
 | 
						|
			Edited by M. Abramowitz and I.A. Stegun
 | 
						|
			National Bureau of Standards
 | 
						|
			Applied Mathematics Series 55
 | 
						|
	*)
 | 
						|
 | 
						|
  CONST
 | 
						|
	OneRadianInDegrees	= 57.295779513082320876798155D;
 | 
						|
	OneDegreeInRadians	=  0.017453292519943295769237D;
 | 
						|
 | 
						|
  (* basic functions *)
 | 
						|
 | 
						|
  PROCEDURE pow(x: REAL; i: INTEGER): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longpow(LONG(x), i));
 | 
						|
  END pow;
 | 
						|
 | 
						|
  PROCEDURE longpow(x: LONGREAL; i: INTEGER): LONGREAL;
 | 
						|
    VAR
 | 
						|
	val: LONGREAL;
 | 
						|
	ri: LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	ri := FLOATD(i);
 | 
						|
	IF x < 0.0D THEN
 | 
						|
		val := longexp(longln(-x) * ri);
 | 
						|
		IF ODD(i) THEN RETURN -val;
 | 
						|
		ELSE RETURN val;
 | 
						|
		END;
 | 
						|
	ELSIF x = 0.0D THEN
 | 
						|
		RETURN 0.0D;
 | 
						|
	ELSE
 | 
						|
		RETURN longexp(longln(x) * ri);
 | 
						|
	END;
 | 
						|
  END longpow;
 | 
						|
 | 
						|
  PROCEDURE sqrt(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longsqrt(LONG(x)));
 | 
						|
  END sqrt;
 | 
						|
 | 
						|
  PROCEDURE longsqrt(x: LONGREAL): LONGREAL;
 | 
						|
    VAR
 | 
						|
	temp: LONGREAL;
 | 
						|
	exp, i: INTEGER;
 | 
						|
  BEGIN
 | 
						|
	IF x <= 0.0D THEN
 | 
						|
		IF x < 0.0D THEN
 | 
						|
			Message("sqrt: negative argument");
 | 
						|
			HALT
 | 
						|
		END;
 | 
						|
		RETURN 0.0D;
 | 
						|
	END;
 | 
						|
	temp := FEF(x,exp);
 | 
						|
	(*
 | 
						|
	 * NOTE
 | 
						|
	 * this wont work on 1's comp
 | 
						|
	 *)
 | 
						|
	IF ODD(exp) THEN
 | 
						|
		temp := 2.0D * temp;
 | 
						|
		DEC(exp);
 | 
						|
	END;
 | 
						|
	temp := 0.5D*(1.0D + temp);
 | 
						|
 | 
						|
	WHILE exp > 28 DO
 | 
						|
		temp := temp * 16384.0D;
 | 
						|
		exp := exp - 28;
 | 
						|
	END;
 | 
						|
	WHILE exp < -28 DO
 | 
						|
		temp := temp / 16384.0D;
 | 
						|
		exp := exp + 28;
 | 
						|
	END;
 | 
						|
	WHILE exp >= 2 DO
 | 
						|
		temp := temp * 2.0D;
 | 
						|
		exp := exp - 2;
 | 
						|
	END;
 | 
						|
	WHILE exp <= -2 DO
 | 
						|
		temp := temp / 2.0D;
 | 
						|
		exp := exp + 2;
 | 
						|
	END;
 | 
						|
	FOR i := 0 TO 4 DO
 | 
						|
		temp := 0.5D*(temp + x/temp);
 | 
						|
	END;
 | 
						|
	RETURN temp;
 | 
						|
  END longsqrt;
 | 
						|
 | 
						|
  PROCEDURE exp(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longexp(LONG(x)));
 | 
						|
  END exp;
 | 
						|
 | 
						|
  PROCEDURE longexp(x: LONGREAL): LONGREAL;
 | 
						|
  (*
 | 
						|
   * n = floor(x / ln2), d = x / ln2 - n
 | 
						|
   * exp(x) = exp((x / ln2) * ln2) = exp((n + d) * ln2) =
 | 
						|
   * exp(n * ln2) * exp(d * ln2) = 2 ** n * exp(d * ln2)
 | 
						|
   *)
 | 
						|
    CONST
 | 
						|
	a1 = -0.9999999995D;
 | 
						|
	a2 =  0.4999999206D;
 | 
						|
	a3 = -0.1666653019D;
 | 
						|
	a4 =  0.0416573475D;
 | 
						|
	a5 = -0.0083013598D;
 | 
						|
	a6 =  0.0013298820D;
 | 
						|
	a7 = -0.0001413161D;
 | 
						|
    VAR
 | 
						|
	neg: BOOLEAN;
 | 
						|
	polval: LONGREAL;
 | 
						|
	n: LONGREAL;
 | 
						|
	n1 : INTEGER;
 | 
						|
  BEGIN
 | 
						|
	neg := x < 0.0D;
 | 
						|
	IF neg THEN
 | 
						|
		x := -x;
 | 
						|
	END;
 | 
						|
	x := FIF(x, 1.0D/LONG(ln2), n) * LONG(ln2);
 | 
						|
	polval := 1.0D /(1.0D + x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*(a6+x*a7)))))));
 | 
						|
	n1 := TRUNCD(n + 0.5D);
 | 
						|
	WHILE n1 >= 16 DO
 | 
						|
		polval := polval * 65536.0D;
 | 
						|
		n1 := n1 - 16;
 | 
						|
	END;
 | 
						|
	WHILE n1 > 0 DO
 | 
						|
		polval := polval * 2.0D;
 | 
						|
		DEC(n1);
 | 
						|
	END;
 | 
						|
	IF neg THEN RETURN 1.0D/polval; END;
 | 
						|
	RETURN polval;
 | 
						|
  END longexp;
 | 
						|
 | 
						|
  PROCEDURE ln(x: REAL): REAL;	(* natural log *)
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longln(LONG(x)));
 | 
						|
  END ln;
 | 
						|
 | 
						|
  PROCEDURE longln(x: LONGREAL): LONGREAL;	(* natural log *)
 | 
						|
    CONST
 | 
						|
	a1 =  0.9999964239D;
 | 
						|
	a2 = -0.4998741238D;
 | 
						|
	a3 =  0.3317990258D;
 | 
						|
	a4 = -0.2407338084D;
 | 
						|
	a5 =  0.1676540711D;
 | 
						|
	a6 = -0.0953293897D;
 | 
						|
	a7 =  0.0360884937D;
 | 
						|
	a8 = -0.0064535442D;
 | 
						|
    VAR
 | 
						|
	exp: INTEGER;
 | 
						|
	polval: LONGREAL;
 | 
						|
 | 
						|
  BEGIN
 | 
						|
	IF x <= 0.0D THEN
 | 
						|
		Message("ln: argument <= 0");
 | 
						|
		HALT
 | 
						|
	END;
 | 
						|
	x := FEF(x, exp);
 | 
						|
	WHILE x < 1.0D DO
 | 
						|
		x := x + x;
 | 
						|
		DEC(exp);
 | 
						|
	END;
 | 
						|
	x := x - 1.0D;
 | 
						|
	polval := x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*(a6+x*(a7+a8*x)))))));
 | 
						|
	RETURN polval + FLOATD(exp) * LONG(ln2);
 | 
						|
  END longln;
 | 
						|
 | 
						|
  PROCEDURE log(x: REAL): REAL;	(* log with base 10 *)
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longlog(LONG(x)));
 | 
						|
  END log;
 | 
						|
 | 
						|
  PROCEDURE longlog(x: LONGREAL): LONGREAL;	(* log with base 10 *)
 | 
						|
  BEGIN
 | 
						|
	RETURN longln(x)/LONG(ln10);
 | 
						|
  END longlog;
 | 
						|
 | 
						|
  (* trigonometric functions; arguments in radians *)
 | 
						|
 | 
						|
  PROCEDURE sin(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longsin(LONG(x)));
 | 
						|
  END sin;
 | 
						|
 | 
						|
  PROCEDURE longsin(x: LONGREAL): LONGREAL;
 | 
						|
    CONST
 | 
						|
	a2  = -0.1666666664D;
 | 
						|
	a4  =  0.0083333315D;
 | 
						|
	a6  = -0.0001984090D;
 | 
						|
	a8  =  0.0000027526D;
 | 
						|
	a10 = -0.0000000239D;
 | 
						|
    VAR
 | 
						|
	xsqr: LONGREAL;
 | 
						|
	neg: BOOLEAN;
 | 
						|
  BEGIN
 | 
						|
	neg := FALSE;
 | 
						|
	IF x < 0.0D THEN
 | 
						|
		neg := TRUE;
 | 
						|
		x := -x;
 | 
						|
	END;
 | 
						|
	x := FIF(x, 1.0D / LONG(twicepi), (* dummy *) xsqr) * LONG(twicepi);
 | 
						|
	IF x >= LONG(pi) THEN
 | 
						|
		neg := NOT neg;
 | 
						|
		x := x - LONG(pi);
 | 
						|
	END;
 | 
						|
	IF x > LONG(halfpi) THEN
 | 
						|
		x := LONG(pi) - x;
 | 
						|
	END;
 | 
						|
	xsqr := x * x;
 | 
						|
	x := x * (1.0D + xsqr*(a2+xsqr*(a4+xsqr*(a6+xsqr*(a8+xsqr*a10)))));
 | 
						|
	IF neg THEN RETURN -x; END;
 | 
						|
	RETURN x;
 | 
						|
  END longsin;
 | 
						|
 | 
						|
  PROCEDURE cos(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longcos(LONG(x)));
 | 
						|
  END cos;
 | 
						|
 | 
						|
  PROCEDURE longcos(x: LONGREAL): LONGREAL;
 | 
						|
    CONST
 | 
						|
	a2  = -0.4999999963D;
 | 
						|
	a4  =  0.0416666418D;
 | 
						|
	a6  = -0.0013888397D;
 | 
						|
	a8  =  0.0000247609D;
 | 
						|
	a10 = -0.0000002605D;
 | 
						|
    VAR
 | 
						|
	xsqr: LONGREAL;
 | 
						|
	neg: BOOLEAN;
 | 
						|
  BEGIN
 | 
						|
	neg := FALSE;
 | 
						|
	IF x < 0.0D THEN x := -x; END;
 | 
						|
	x := FIF(x, 1.0D / LONG(twicepi), (* dummy *) xsqr) * LONG(twicepi);
 | 
						|
	IF x >= LONG(pi) THEN
 | 
						|
		x := LONG(twicepi) - x;
 | 
						|
	END;
 | 
						|
	IF x > LONG(halfpi) THEN
 | 
						|
		neg := NOT neg;
 | 
						|
		x := LONG(pi) - x;
 | 
						|
	END;
 | 
						|
	xsqr := x * x;
 | 
						|
	x := 1.0D + xsqr*(a2+xsqr*(a4+xsqr*(a6+xsqr*(a8+xsqr*a10))));
 | 
						|
	IF neg THEN RETURN -x; END;
 | 
						|
	RETURN x;
 | 
						|
  END longcos;
 | 
						|
 | 
						|
  PROCEDURE tan(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longtan(LONG(x)));
 | 
						|
  END tan;
 | 
						|
 | 
						|
  PROCEDURE longtan(x: LONGREAL): LONGREAL;
 | 
						|
    VAR cosinus: LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	cosinus := longcos(x);
 | 
						|
	IF cosinus = 0.0D THEN
 | 
						|
		Message("tan: result does not exist");
 | 
						|
		HALT
 | 
						|
	END;
 | 
						|
	RETURN longsin(x)/cosinus;
 | 
						|
  END longtan;
 | 
						|
 | 
						|
  PROCEDURE arcsin(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longarcsin(LONG(x)));
 | 
						|
  END arcsin;
 | 
						|
 | 
						|
  PROCEDURE longarcsin(x: LONGREAL): LONGREAL;
 | 
						|
    CONST
 | 
						|
	a0 =  1.5707963050D;
 | 
						|
	a1 = -0.2145988016D;
 | 
						|
	a2 =  0.0889789874D;
 | 
						|
	a3 = -0.0501743046D;
 | 
						|
	a4 =  0.0308918810D;
 | 
						|
	a5 = -0.0170881256D;
 | 
						|
	a6 =  0.0066700901D;
 | 
						|
	a7 = -0.0012624911D;
 | 
						|
  BEGIN
 | 
						|
	IF x < 0.0D THEN x := -x; END;
 | 
						|
	IF x > 1.0D THEN
 | 
						|
		Message("arcsin: argument > 1");
 | 
						|
		HALT
 | 
						|
	END;
 | 
						|
	RETURN LONG(halfpi) -
 | 
						|
		longsqrt(1.0D - x)*(a0+x*(a1+x*(a2+x*(a3+x*(a4+x*(a5+x*(a6+x*a7)))))));
 | 
						|
  END longarcsin;
 | 
						|
 | 
						|
  PROCEDURE arccos(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longarccos(LONG(x)));
 | 
						|
  END arccos;
 | 
						|
 | 
						|
  PROCEDURE longarccos(x: LONGREAL): LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN LONG(halfpi) - longarcsin(x);
 | 
						|
  END longarccos;
 | 
						|
 | 
						|
  PROCEDURE arctan(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longarctan(LONG(x)));
 | 
						|
  END arctan;
 | 
						|
 | 
						|
  PROCEDURE longarctan(x: LONGREAL): LONGREAL;
 | 
						|
    CONST
 | 
						|
	a2  = -0.3333314528D;
 | 
						|
	a4  =  0.1999355085D;
 | 
						|
	a6  = -0.1420889944D;
 | 
						|
	a8  =  0.1065626393D;
 | 
						|
	a10 = -0.0752896400D;
 | 
						|
	a12 =  0.0429096318D;
 | 
						|
	a14 = -0.0161657367D;
 | 
						|
	a16 =  0.0028662257D;
 | 
						|
    VAR
 | 
						|
	xsqr: LONGREAL;
 | 
						|
	rev: BOOLEAN;
 | 
						|
	neg: BOOLEAN;
 | 
						|
  BEGIN
 | 
						|
	rev := FALSE;
 | 
						|
	neg := FALSE;
 | 
						|
	IF x < 0.0D THEN
 | 
						|
		neg := TRUE;
 | 
						|
		x := -x;
 | 
						|
	END;
 | 
						|
	IF x > 1.0D THEN
 | 
						|
		rev := TRUE;
 | 
						|
		x := 1.0D / x;
 | 
						|
	END;
 | 
						|
	xsqr := x * x;
 | 
						|
	x := x * (1.0D + xsqr*(a2+xsqr*(a4+xsqr*(a6+xsqr*(a8+xsqr*(a10+xsqr*(a12+xsqr*(a14+xsqr*a16))))))));
 | 
						|
	IF rev THEN
 | 
						|
		x := LONG(quartpi) - x;
 | 
						|
	END;
 | 
						|
	IF neg THEN RETURN -x; END;
 | 
						|
	RETURN x;
 | 
						|
  END longarctan;
 | 
						|
 | 
						|
  (* hyperbolic functions *)
 | 
						|
 | 
						|
  PROCEDURE sinh(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longsinh(LONG(x)));
 | 
						|
  END sinh;
 | 
						|
 | 
						|
  PROCEDURE longsinh(x: LONGREAL): LONGREAL;
 | 
						|
    VAR expx: LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	expx := longexp(x);
 | 
						|
	RETURN (expx - 1.0D/expx)/2.0D;
 | 
						|
  END longsinh;
 | 
						|
 | 
						|
  PROCEDURE cosh(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longcosh(LONG(x)));
 | 
						|
  END cosh;
 | 
						|
 | 
						|
  PROCEDURE longcosh(x: LONGREAL): LONGREAL;
 | 
						|
    VAR expx: LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	expx := longexp(x);
 | 
						|
	RETURN (expx + 1.0D/expx)/2.0D;
 | 
						|
  END longcosh;
 | 
						|
 | 
						|
  PROCEDURE tanh(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longtanh(LONG(x)));
 | 
						|
  END tanh;
 | 
						|
 | 
						|
  PROCEDURE longtanh(x: LONGREAL): LONGREAL;
 | 
						|
    VAR expx: LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	expx := longexp(x);
 | 
						|
	RETURN (expx - 1.0D/expx) / (expx + 1.0D/expx);
 | 
						|
  END longtanh;
 | 
						|
 | 
						|
  PROCEDURE arcsinh(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longarcsinh(LONG(x)));
 | 
						|
  END arcsinh;
 | 
						|
 | 
						|
  PROCEDURE longarcsinh(x: LONGREAL): LONGREAL;
 | 
						|
    VAR neg: BOOLEAN;
 | 
						|
  BEGIN
 | 
						|
	neg := FALSE;
 | 
						|
	IF x < 0.0D THEN
 | 
						|
		neg := TRUE;
 | 
						|
		x := -x;
 | 
						|
	END;
 | 
						|
	x := longln(x + longsqrt(x*x+1.0D));
 | 
						|
	IF neg THEN RETURN -x; END;
 | 
						|
	RETURN x;
 | 
						|
  END longarcsinh;
 | 
						|
 | 
						|
  PROCEDURE arccosh(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longarccosh(LONG(x)));
 | 
						|
  END arccosh;
 | 
						|
 | 
						|
  PROCEDURE longarccosh(x: LONGREAL): LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	IF x < 1.0D THEN
 | 
						|
		Message("arccosh: argument < 1");
 | 
						|
		HALT
 | 
						|
	END;
 | 
						|
	RETURN longln(x + longsqrt(x*x - 1.0D));
 | 
						|
  END longarccosh;
 | 
						|
 | 
						|
  PROCEDURE arctanh(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longarctanh(LONG(x)));
 | 
						|
  END arctanh;
 | 
						|
 | 
						|
  PROCEDURE longarctanh(x: LONGREAL): LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	IF (x <= -1.0D) OR (x >= 1.0D) THEN
 | 
						|
		Message("arctanh: ABS(argument) >= 1");
 | 
						|
		HALT
 | 
						|
	END;
 | 
						|
	RETURN longln((1.0D + x)/(1.0D - x)) / 2.0D;
 | 
						|
  END longarctanh;
 | 
						|
 | 
						|
  (* conversions *)
 | 
						|
 | 
						|
  PROCEDURE RadianToDegree(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longRadianToDegree(LONG(x)));
 | 
						|
  END RadianToDegree;
 | 
						|
 | 
						|
  PROCEDURE longRadianToDegree(x: LONGREAL): LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN x * OneRadianInDegrees;
 | 
						|
  END longRadianToDegree;
 | 
						|
 | 
						|
  PROCEDURE DegreeToRadian(x: REAL): REAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN SHORT(longDegreeToRadian(LONG(x)));
 | 
						|
  END DegreeToRadian;
 | 
						|
 | 
						|
  PROCEDURE longDegreeToRadian(x: LONGREAL): LONGREAL;
 | 
						|
  BEGIN
 | 
						|
	RETURN x * OneDegreeInRadians;
 | 
						|
  END longDegreeToRadian;
 | 
						|
 | 
						|
END Mathlib.
 |