|
|
1.1 root 1: (* Copyright 1989 by AT&T Bell Laboratories *)
2: (* The following functions were adapted from the 4.3BSD math library.
3: Eventually, each machine supported should have a hand-coded math
4: functor with more efficient versions of these functions.
5:
6: ***************************************************************************
7: * *
8: * Copyright (c) 1985 Regents of the University of California. *
9: * *
10: * Use and reproduction of this software are granted in accordance with *
11: * the terms and conditions specified in the Berkeley Software License *
12: * Agreement (in particular, this entails acknowledgement of the programs' *
13: * source, and inclusion of this notice) with the additional understanding *
14: * that all recipients should regard themselves as participants in an *
15: * ongoing research project and hence should feel obligated to report *
16: * their experiences (good or bad) with these elementary function codes, *
17: * using "sendbug 4bsd-bugs@BERKELEY", to the authors. *
18: * *
19: * K.C. Ng, with Z-S. Alex Liu, S. McDonald, P. Tang, W. Kahan. *
20: * Revised on 5/10/85, 5/13/85, 6/14/85, 8/20/85, 8/27/85, 9/11/85. *
21: * *
22: ***************************************************************************
23:
24: *)
25:
26: signature MATH =
27: sig
28: exception Sqrt and Exp and Ln
29: val sqrt : real -> real
30: val sin : real -> real
31: val cos : real -> real
32: val arctan : real -> real
33: val exp : real -> real
34: val ln : real -> real
35: end
36:
37: structure Math : MATH = struct
38:
39: structure Assembly : ASSEMBLY = Core.Assembly
40:
41: infix 7 * /
42: infix 6 + -
43: infix 4 > < >= <=
44:
45: exception Real = Assembly.Real
46: exception Sqrt
47: exception Exp
48: exception Ln
49:
50: val scalb = Assembly.A.scalb
51: val logb = Assembly.A.logb
52:
53: val ~ = InLine.fneg
54: val op + = InLine.fadd
55: val op - = InLine.fsub
56: val op * = InLine.fmul
57: val op / = InLine.fdiv
58: val op > = InLine.fgt
59: val op < = InLine.flt
60: val op >= = InLine.fge
61: val op <= = InLine.fle
62:
63: val ieql = InLine.ieql
64: val ineq = InLine.ineq
65: val feql = InLine.feql
66:
67: val negone = ~1.0
68: val zero = 0.0
69: val half = 0.5
70: val one = 1.0
71: val two = 2.0
72: val four = 4.0
73:
74: fun copysign(a,b) =
75: case (a<zero,b<zero) of
76: (true,true) => a
77: | (false,false) => a
78: | _ => ~a
79:
80: fun abs x = if x < zero then ~x else x
81: fun mod(a,b) = InLine.-(a,InLine.*(InLine.div(a,b),b))
82: local fun rtoi (pred,init) =
83: let fun loop n =
84: if pred n
85: then init
86: else let val (i,r) = loop(n * half)
87: val i' = InLine.lshift(i,1)
88: val r' = r+r
89: in if n-r' < one then (i',r') else (InLine.+(i',1),r'+one)
90: end
91: in loop
92: end
93: val pton = rtoi(fn x => x < one, (0,zero))
94: val nton = rtoi(fn x => x >= negone, (~1,negone))
95: fun fl n = if n < zero then nton n else pton n
96: fun tr n = #1(pton n)
97: in
98: fun truncate n = if n < zero then InLine.~(tr(~n)) else tr n
99: val floor = Assembly.A.floor
100: fun realfloor n = #2(fl n)
101: fun ceiling n = InLine.~(floor(~n))
102: end
103: local fun loop 0 = zero
104: | loop n = let val x = two * loop(InLine.rshift(n,1))
105: in case InLine.andb(n,1) of 0 => x | 1 => x + one
106: end
107: in fun real n = if InLine.<(n,0) then ~(loop(InLine.~ n)) else loop n
108: end
109:
110: (* Not a true drem - rounding on .5 should go to the even case. *)
111: fun drem(x,y) =
112: let val n = x/y+half
113: val N = if abs n < 9.007199254741E15 (* about 2^53 *)
114: then realfloor n
115: handle Real _ =>
116: scalb(realfloor(scalb(n,InLine.~(logb n))),logb n)
117: else n
118: in x - N * y
119: end
120:
121: (* sin/cos *)
122: local
123: val S0 = ~1.6666666666666463126E~1
124: val S1 = 8.3333333332992771264E~3
125: val S2 = ~1.9841269816180999116E~4
126: val S3 = 2.7557309793219876880E~6
127: val S4 = ~2.5050225177523807003E~8
128: val S5 = 1.5868926979889205164E~10
129: in fun sin__S z = (z*(S0+z*(S1+z*(S2+z*(S3+z*(S4+z*S5))))))
130: end
131:
132: local
133: val C0 = 4.1666666666666504759E~2
134: val C1 = ~1.3888888888865301516E~3
135: val C2 = 2.4801587269650015769E~5
136: val C3 = ~2.7557304623183959811E~7
137: val C4 = 2.0873958177697780076E~9
138: val C5 = ~1.1250289076471311557E~11
139: in fun cos__C z = (z*z*(C0+z*(C1+z*(C2+z*(C3+z*(C4+z*C5))))))
140: end
141:
142: val PIo4 = 7.8539816339744827900E~1
143: val PIo2 = 1.5707963267948965580E0
144: val PI3o4 = 2.3561944901923448370E0
145: val PI = 3.1415926535897931160E0
146: val PI2 = 6.2831853071795862320E0
147:
148: local
149: val thresh = 2.6117239648121182150E~1
150: in fun S y = y + y * sin__S(y*y)
151: fun C y =
152: let val yy = y*y
153: val c = cos__C yy
154: val Y = yy/two
155: in if Y < thresh then one - (Y - c)
156: else half - (Y - half - c)
157: end
158: end
159: fun sin x =
160: let val x = drem(x,PI2)
161: val a = abs x
162: val y = if a >= PI3o4 then copysign(PI-a,x) else a
163: in if y >= PIo4 then copysign(C(PIo2-a),x)
164: else S y
165: end
166:
167: fun cos x =
168: let val x = drem(x,PI2)
169: val a = abs x
170: val (s,y) = if a >= PI3o4
171: then (fn x => ~x,PI-a)
172: else (fn x => x,a)
173: in if y < PIo4 then s(C y)
174: else S(PIo2-a)
175: end
176:
177: local
178: val p1 = 1.3887401997267371720E~2
179: val p2 = 3.3044019718331897649E~5
180: val q1 = 1.1110813732786649355E~1
181: val q2 = 9.9176615021572857300E~4
182: in fun exp__E(x:real,c:real) =
183: let val small=1.0E~19
184: val x = abs x
185: val z = x*x
186: val p = z*(p1+z*p2)
187: val q = z*(q1+z*q2)
188: val xp= x*p
189: val xh= x*half
190: val w = xh-(q-xp)
191: val p = p+p
192: val c = c+x*((xh*w-(q-(p+xp)))/(one-w)+c)
193: in if(copysign(x,one)>small) then z*half+c
194: else copysign(zero,x) (* could be inexact *)
195: end
196: end
197:
198: (* for exp and ln *)
199: val ln2hi = 6.9314718036912381649E~1
200: val ln2lo = 1.9082149292705877000E~10
201: val sqrt2 = 1.4142135623730951455E0
202: val lnhuge = 7.1602103751842355450E2
203: val lntiny = ~7.5137154372698068983E2
204: val invln2 = 1.4426950408889633870E0
205:
206: fun exp(x:real) =
207: let fun exp_norm() =
208: let (* argument reduction : x --> x - k*ln2 *)
209: val k = floor(invln2*x+copysign(half,x)) (* k=NINT(x/ln2) *)
210: val K = real k
211: (* express x-k*ln2 as z+c *)
212: val hi = x-K*ln2hi
213: val lo = K*ln2lo
214: val z = hi - lo
215: val c = (hi-z)-lo
216: (* return 2^k*[expm1(x) + 1] *)
217: val z = z + exp__E(z,c)
218: in scalb(z+one,k)
219: end
220: in if x <= lnhuge then if x >= lntiny
221: then exp_norm() handle Real _ => raise Exp
222: else zero (* exp(-big#) underflows to zero *)
223: (* exp(-INF) is zero *)
224: else raise Exp (* exp(INF) is INF, exp(+big#) overflows to INF *)
225: end
226:
227: local
228: val L1 = 6.6666666666667340202E~1
229: val L2 = 3.9999999999416702146E~1
230: val L3 = 2.8571428742008753154E~1
231: val L4 = 2.2222198607186277597E~1
232: val L5 = 1.8183562745289935658E~1
233: val L6 = 1.5314087275331442206E~1
234: val L7 = 1.4795612545334174692E~1
235: in fun log__L(z) = z*(L1+z*(L2+z*(L3+z*(L4+z*(L5+z*(L6+z*L7))))))
236: end
237:
238: fun ln(x:real) =
239: let fun findln() =
240: let (* argument reduction *)
241: val k = logb(x)
242: val x = scalb(x,InLine.~ k)
243: val (x,k) = if ieql(k,~1022) (* subnormal no. *)
244: then let val n = logb(x)
245: in (scalb(x,InLine.~ n),InLine.+(k,n)) end
246: else (x,k)
247: val (k,x) = if x >= sqrt2 then (InLine.+(k,1),x*half) else (k,x)
248: val K = real k
249: val x = x - one
250: (* compute log(1+x) *)
251: val s = x/(two+x)
252: val t = x*x*half
253: val z = K*ln2lo+s*(t+log__L(s*s))
254: val x = x + (z - t)
255: in K*ln2hi+x end
256: in if x <= zero then raise Ln
257: else findln() handle Real _ => raise Ln
258: end
259:
260: local
261: val small=1.0E~9
262: val big=1.0E18
263: val athfhi = 4.6364760900080609352E~1
264: val athflo = 4.6249969567426939759E~18
265: val at1fhi = 9.8279372324732905408E~1
266: val at1flo = ~2.4407677060164810007E~17
267: val a1 = 3.3333333333333942106E~1
268: val a2 = ~1.9999999999979536924E~1
269: val a3 = 1.4285714278004377209E~1
270: val a4 = ~1.1111110579344973814E~1
271: val a5 = 9.0908906105474668324E~2
272: val a6 = ~7.6919217767468239799E~2
273: val a7 = 6.6614695906082474486E~2
274: val a8 = ~5.8358371008508623523E~2
275: val a9 = 4.9850617156082015213E~2
276: val a10 = ~3.6700606902093604877E~2
277: val a11 = 1.6438029044759730479E~2
278: in
279: fun atan2(y:real,x:real) =
280: let (* copy down the sign of y and x *)
281: val signy = copysign(one,y)
282: val signx = copysign(one,x)
283: exception Done of real
284: fun findatan2(x,y,t) =
285: let (* begin argument reduction *)
286: val k = floor(four * (t+0.0625))
287: val (hi,lo,t) =
288: if t < 2.4375 then
289: (* truncate 4(t+1/16) to integer for branching *)
290: case k of
291: (* t is in [0,7/16] *)
292: 0 => if t < small
293: then raise Done
294: (copysign(if signx>zero then t
295: else PI-t,
296: signy))
297: else (zero,zero,t)
298: | 1 => if t < small
299: then raise Done
300: (copysign(if signx>zero then t
301: else PI-t,
302: signy))
303: else (zero,zero,t)
304: (* t is in [7/16,11/16] *)
305: | 2 => (athfhi,athflo,((y+y)-x)/(x+x+y))
306: (* t is in [11/16,19/16] *)
307: | 3 => (PIo4,zero,(y-x)/(x+y))
308: | 4 => (PIo4,zero,(y-x)/(x+y))
309: (* t is in [19/16,39/16] *)
310: | _ => let val z = y-x
311: val y = y+y+y
312: val t = x+x
313: in (at1fhi,at1flo,( (z+z)-x ) / ( t + y ))
314: end
315: (* end of if (t < 2.4375) *)
316: else let val t = if t <= big
317: (* t is in [2.4375, big] *)
318: then ~x / y
319: (* t is in [big, INF] *)
320: else zero
321: in (PIo2,zero,t) end
322: (* end of argument reduction *)
323: (* compute atan(t) for t in [~.4375, .4375] *)
324: val z = t*t
325: val z = t*(z*(a1+z*(a2+z*(a3+z*(a4+z*(a5+z*(a6+z*(a7+z*(a8+
326: z*(a9+z*(a10+z*a11)))))))))))
327: val z = lo - z
328: val z = z + t
329: val z = z + hi
330: in copysign(if signx>zero then z else PI-z,signy)
331: end
332: in
333: (* if x is 1.0, compute *)
334: if feql(x,one) then findatan2(x,copysign(y,one),y) handle Done r => r
335: (* when y = 0 *)
336: else if feql(y,zero) then if feql(signx,one) then y else copysign(PI,signy)
337: (* when x = 0 *)
338: else if feql(x,zero) then copysign(PIo2,signy)
339: else (* compute y/x *)
340: let val x = copysign(x,one)
341: val y = copysign(y,one)
342: val k = logb(y)
343: val m = InLine.-(k,logb(x))
344: val (t,y,x) = if InLine.>(m,60) then (big+big,y,x)
345: else if InLine.<(m,~80) then (y/x,y,x)
346: else (y/x,scalb(y,InLine.~ k),
347: scalb(x,InLine.~ k))
348: in findatan2(x,y,t) handle Done r => r end
349: end
350: end
351:
352: fun arctan(x:real) = atan2(x,one)
353:
354: fun sqrt(x: real) =
355: if x<=zero then if x<zero then raise Sqrt else x
356: else
357: let val k = 6 (* log base 2 of the precision *)
358: val n = InLine.rshift(logb(x),1)
359: val x = scalb(x, InLine.~(InLine.lshift(n,1)))
360: fun iter(0,g) = g
361: | iter(i,g) = iter(InLine.-(i,1), half * (g + x/g))
362: in scalb(iter(k,one),n)
363: end
364:
365: end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.