Annotation of researchv10no/cmd/sml/src/boot/math.sml, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.