2 (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
3 See the copyright notice in the ACK home directory, in the file "Copyright".
7 IMPLEMENTATION MODULE Mathlib
;
9 Module: Mathematical functions
10 Author: Ceriel J.H. Jacobs
14 FROM EM
IMPORT FIF
, FEF
;
15 FROM Traps
IMPORT Message
;
18 OneRadianInDegrees
= 57.295779513082320876798155D
;
19 OneDegreeInRadians
= 0.017453292519943295769237D
;
20 OneOverSqrt2
= 0.70710678118654752440084436210484904D
;
24 PROCEDURE pow(x
: REAL; i
: INTEGER): REAL;
26 RETURN SHORT(longpow(LONG(x
), i
));
29 PROCEDURE longpow(x
: LONGREAL; i
: INTEGER): LONGREAL;
35 val
:= longexp(longln(-x
) * ri
);
36 IF ODD(i
) THEN RETURN -val
;
42 RETURN longexp(longln(x
) * ri
);
46 PROCEDURE sqrt(x
: REAL): REAL;
48 RETURN SHORT(longsqrt(LONG(x
)));
51 PROCEDURE longsqrt(x
: LONGREAL): LONGREAL;
58 Message("sqrt: negative argument");
66 * this wont work on 1's comp
72 temp
:= 0.5D
*(1.0D
+ temp
);
75 temp
:= temp
* 16384.0D
;
79 temp
:= temp
/ 16384.0D
;
91 temp
:= 0.5D
*(temp
+ x
/temp
);
96 PROCEDURE ldexp(x
:LONGREAL; n
: INTEGER): LONGREAL;
117 PROCEDURE exp(x
: REAL): REAL;
119 RETURN SHORT(longexp(LONG(x
)));
122 PROCEDURE longexp(x
: LONGREAL): LONGREAL;
123 (* Algorithm and coefficients from:
124 "Software manual for the elementary functions"
125 by W.J. Cody and W. Waite, Prentice-Hall, 1980
128 p0
= 0.25000000000000000000D
+00;
129 p1
= 0.75753180159422776666D
-02;
130 p2
= 0.31555192765684646356D
-04;
131 q0
= 0.50000000000000000000D
+00;
132 q1
= 0.56817302698551221787D
-01;
133 q2
= 0.63121894374398503557D
-03;
134 q3
= 0.75104028399870046114D
-06;
139 xn
, g
, x1
, x2
: LONGREAL;
145 n
:= TRUNC(x
/longln2
+ 0.5D
);
147 x1
:= FLOATD(TRUNCD(x
));
149 g
:= ((x1
- xn
* 0.693359375D
)+x2
) - xn
* (-2.1219444005469058277D
-4);
155 x
:= g
*((p2
*xn
+p1
)*xn
+p0
);
157 RETURN ldexp(0.5D
+ x
/((((q3
*xn
+q2
)*xn
+q1
)*xn
+q0
) - x
), n
);
160 PROCEDURE ln(x
: REAL): REAL; (* natural log *)
162 RETURN SHORT(longln(LONG(x
)));
165 PROCEDURE longln(x
: LONGREAL): LONGREAL; (* natural log *)
166 (* Algorithm and coefficients from:
167 "Software manual for the elementary functions"
168 by W.J. Cody and W. Waite, Prentice-Hall, 1980
171 p0
= -0.64124943423745581147D
+02;
172 p1
= 0.16383943563021534222D
+02;
173 p2
= -0.78956112887491257267D
+00;
174 q0
= -0.76949932108494879777D
+03;
175 q1
= 0.31203222091924532844D
+03;
176 q2
= -0.35667977739034646171D
+02;
180 z
, znum
, zden
, w
: LONGREAL;
184 Message("ln: argument <= 0");
188 IF x
> OneOverSqrt2
THEN
189 znum
:= (x
- 0.5D
) - 0.5D
;
190 zden
:= x
* 0.5D
+ 0.5D
;
193 zden
:= znum
* 0.5D
+ 0.5D
;
198 x
:= z
+ z
* w
* (((p2
*w
+p1
)*w
+p0
)/(((q3
*w
+q2
)*w
+q1
)*w
+q0
));
200 x
:= x
+ z
* (-2.121944400546905827679D
-4);
201 RETURN x
+ z
* 0.693359375D
;
204 PROCEDURE log(x
: REAL): REAL; (* log with base 10 *)
206 RETURN SHORT(longlog(LONG(x
)));
209 PROCEDURE longlog(x
: LONGREAL): LONGREAL; (* log with base 10 *)
211 RETURN longln(x
)/longln10
;
214 (* trigonometric functions; arguments in radians *)
216 PROCEDURE sin(x
: REAL): REAL;
218 RETURN SHORT(longsin(LONG(x
)));
221 PROCEDURE sinus(x
: LONGREAL; cosflag
: BOOLEAN) : LONGREAL;
222 (* Algorithm and coefficients from:
223 "Software manual for the elementary functions"
224 by W.J. Cody and W. Waite, Prentice-Hall, 1980
227 r0
= -0.16666666666666665052D
+00;
228 r1
= 0.83333333333331650314D
-02;
229 r2
= -0.19841269841201840457D
-03;
230 r3
= 0.27557319210152756119D
-05;
231 r4
= -0.25052106798274584544D
-07;
232 r5
= 0.16058936490371589114D
-09;
233 r6
= -0.76429178068910467734D
-12;
234 r7
= 0.27204790957888846175D
-14;
236 A2
= -8.908910206761537356617D
-6;
238 x1
, x2
, y
: LONGREAL;
252 y
:= y
/ longpi
+ 0.5D
;
254 IF FIF(y
, 1.0D
, y
) < 0.0D
THEN ; END;
255 IF FIF(y
, 0.5D
, x1
) #
0.0D
THEN neg
:= NOT neg
END;
256 IF cosflag
THEN y
:= y
- 0.5D
END;
257 x2
:= FIF(x
, 1.0, x1
);
267 x
:= x
+ x
* y
* (((((((r7
*y
+r6
)*y
+r5
)*y
+r4
)*y
+r3
)*y
+r2
)*y
+r1
)*y
+r0
);
268 IF neg
THEN RETURN -x
END;
272 PROCEDURE longsin(x
: LONGREAL): LONGREAL;
274 RETURN sinus(x
, FALSE);
277 PROCEDURE cos(x
: REAL): REAL;
279 RETURN SHORT(longcos(LONG(x
)));
282 PROCEDURE longcos(x
: LONGREAL): LONGREAL;
284 IF x
< 0.0D
THEN x
:= -x
; END;
285 RETURN sinus(x
, TRUE);
288 PROCEDURE tan(x
: REAL): REAL;
290 RETURN SHORT(longtan(LONG(x
)));
293 PROCEDURE longtan(x
: LONGREAL): LONGREAL;
294 (* Algorithm and coefficients from:
295 "Software manual for the elementary functions"
296 by W.J. Cody and W. Waite, Prentice-Hall, 1980
300 p1
= -0.13338350006421960681D
+00;
301 p2
= 0.34248878235890589960D
-02;
302 p3
= -0.17861707342254426711D
-04;
305 q1
= -0.46671683339755294240D
+00;
306 q2
= 0.25663832289440112864D
-01;
307 q3
= -0.31181531907010027307D
-03;
308 q4
= 0.49819433993786512270D
-06;
311 A2
= -4.454455103380768678308D
-06;
313 VAR y
, x1
, x2
: LONGREAL;
317 negative
:= x
< 0.0D
;
318 y
:= x
/ longhalfpi
+ 0.5D
;
320 (* Use extended precision to calculate reduced argument.
321 Here we used 12 bits of the mantissa for a1.
322 Also split x in integer part x1 and fraction part x2.
324 IF FIF(y
, 1.0D
, y
) < 0.0D
THEN ; END;
325 invert
:= FIF(y
, 0.5D
, x1
) #
0.0D
;
326 x2
:= FIF(x
, 1.0D
, x1
);
332 x
:= x
+ x
* y
* ((p3
*y
+p2
)*y
+p1
);
333 y
:= (((q4
*y
+q3
)*y
+q2
)*y
+q1
)*y
+q0
;
334 IF negative
THEN x
:= -x
END;
335 IF invert
THEN RETURN -y
/x
END;
339 PROCEDURE arcsin(x
: REAL): REAL;
341 RETURN SHORT(longarcsin(LONG(x
)));
344 PROCEDURE arcsincos(x
: LONGREAL; cosfl
: BOOLEAN): LONGREAL;
346 p0
= -0.27368494524164255994D
+02;
347 p1
= 0.57208227877891731407D
+02;
348 p2
= -0.39688862997540877339D
+02;
349 p3
= 0.10152522233806463645D
+02;
350 p4
= -0.69674573447350646411D
+00;
352 q0
= -0.16421096714498560795D
+03;
353 q1
= 0.41714430248260412556D
+03;
354 q2
= -0.38186303361750149284D
+03;
355 q3
= 0.15095270841030604719D
+03;
356 q4
= -0.23823859153670238830D
+02;
363 negative
:= x
< 0.0D
;
364 IF negative
THEN x
:= -x
; END;
368 Message("arcsin or arccos: argument > 1");
371 g
:= 0.5D
- 0.5D
* x
;
379 ((((p4
*g
+p3
)*g
+p2
)*g
+p1
)*g
+p0
)/(((((q5
*g
+q4
)*g
+q3
)*g
+q2
)*g
+q1
)*g
+q0
);
380 IF cosfl
AND NOT negative
THEN x
:= -x
END;
381 IF cosfl
= NOT big
THEN
382 x
:= (x
+ longquartpi
) + longquartpi
;
383 ELSIF cosfl
AND negative
AND big
THEN
384 x
:= (x
+ longhalfpi
) + longhalfpi
;
386 IF negative
AND NOT cosfl
THEN x
:= -x
END;
390 PROCEDURE longarcsin(x
: LONGREAL): LONGREAL;
392 RETURN arcsincos(x
, FALSE);
395 PROCEDURE arccos(x
: REAL): REAL;
397 RETURN SHORT(longarccos(LONG(x
)));
400 PROCEDURE longarccos(x
: LONGREAL): LONGREAL;
402 RETURN arcsincos(x
, TRUE);
405 PROCEDURE arctan(x
: REAL): REAL;
407 RETURN SHORT(longarctan(LONG(x
)));
410 VAR A
: ARRAY[0.
.3] OF LONGREAL;
413 PROCEDURE longarctan(x
: LONGREAL): LONGREAL;
414 (* Algorithm and coefficients from:
415 "Software manual for the elementary functions"
416 by W.J. Cody and W. Waite, Prentice-Hall, 1980
419 p0
= -0.13688768894191926929D
+02;
420 p1
= -0.20505855195861651981D
+02;
421 p2
= -0.84946240351320683534D
+01;
422 p3
= -0.83758299368150059274D
+00;
423 q0
= 0.41066306682575781263D
+02;
424 q1
= 0.86157349597130242515D
+02;
425 q2
= 0.59578436142597344465D
+02;
426 q3
= 0.15024001160028576121D
+02;
433 IF NOT arctaninit
THEN
436 A
[1] := 0.52359877559829887307710723554658381D
; (* p1/6 *)
438 A
[3] := 1.04719755119659774615421446109316763D
; (* pi/3 *)
451 IF x
> 0.26794919243112270647D
(* 2-sqrt(3) *) THEN
453 x
:= (((0.73205080756887729353D
*x
-0.5D
)-0.5D
)+x
)/
454 (1.73205080756887729353D
+ x
);
457 x
:= x
+ x
* g
* (((p3
*g
+p2
)*g
+p1
)*g
+p0
) / ((((q4
*g
+q3
)*g
+q2
)*g
+q1
)*g
+q0
);
458 IF n
> 1 THEN x
:= -x
END;
460 IF neg
THEN RETURN -x
; END;
464 (* hyperbolic functions *)
465 (* The C math library has better implementations for some of these, but
466 they depend on some properties of the floating point implementation,
467 and, for now, we don't want that in the Modula-2 system.
470 PROCEDURE sinh(x
: REAL): REAL;
472 RETURN SHORT(longsinh(LONG(x
)));
475 PROCEDURE longsinh(x
: LONGREAL): LONGREAL;
479 RETURN (expx
- 1.0D
/expx
)/2.0D
;
482 PROCEDURE cosh(x
: REAL): REAL;
484 RETURN SHORT(longcosh(LONG(x
)));
487 PROCEDURE longcosh(x
: LONGREAL): LONGREAL;
491 RETURN (expx
+ 1.0D
/expx
)/2.0D
;
494 PROCEDURE tanh(x
: REAL): REAL;
496 RETURN SHORT(longtanh(LONG(x
)));
499 PROCEDURE longtanh(x
: LONGREAL): LONGREAL;
503 RETURN (expx
- 1.0D
/expx
) / (expx
+ 1.0D
/expx
);
506 PROCEDURE arcsinh(x
: REAL): REAL;
508 RETURN SHORT(longarcsinh(LONG(x
)));
511 PROCEDURE longarcsinh(x
: LONGREAL): LONGREAL;
519 x
:= longln(x
+ longsqrt(x
*x
+1.0D
));
520 IF neg
THEN RETURN -x
; END;
524 PROCEDURE arccosh(x
: REAL): REAL;
526 RETURN SHORT(longarccosh(LONG(x
)));
529 PROCEDURE longarccosh(x
: LONGREAL): LONGREAL;
532 Message("arccosh: argument < 1");
535 RETURN longln(x
+ longsqrt(x
*x
- 1.0D
));
538 PROCEDURE arctanh(x
: REAL): REAL;
540 RETURN SHORT(longarctanh(LONG(x
)));
543 PROCEDURE longarctanh(x
: LONGREAL): LONGREAL;
545 IF (x
<= -1.0D
) OR (x
>= 1.0D
) THEN
546 Message("arctanh: ABS(argument) >= 1");
549 RETURN longln((1.0D
+ x
)/(1.0D
- x
)) / 2.0D
;
554 PROCEDURE RadianToDegree(x
: REAL): REAL;
556 RETURN SHORT(longRadianToDegree(LONG(x
)));
559 PROCEDURE longRadianToDegree(x
: LONGREAL): LONGREAL;
561 RETURN x
* OneRadianInDegrees
;
562 END longRadianToDegree
;
564 PROCEDURE DegreeToRadian(x
: REAL): REAL;
566 RETURN SHORT(longDegreeToRadian(LONG(x
)));
569 PROCEDURE longDegreeToRadian(x
: LONGREAL): LONGREAL;
571 RETURN x
* OneDegreeInRadians
;
572 END longDegreeToRadian
;