|
|
1.1 root 1: (* Copyright 1989 by AT&T Bell Laboratories *)
2: (*
3: RealConst: generate ML real constants.
4: RealConst uses long multiplication to find the correct bit pattern for
5: the real. This method is slow, but accurate, and works to any precision,
6: which means that floats can be cross-compiled correctly.
7:
8: The function emitreal should take (int * bool array * int) which represents
9: a real value as (sign * fraction * exponent).
10: The sign is 0 if the real is positive, 1 if negative.
11: The fraction is a boolean array representing the bits; note that the most
12: significant bit is in position 0.
13: The exponent is the binary exponent of the normalized fraction.
14: "Normalized" here means a number between 0 and 1.
15:
16: The algorithm works inefficient on forms like 10000000.0; forms like 1E7 (with
17: no bogus zeros) are better. Also inefficient on forms like 0E23 or 1E~212.
18: *)
19:
20: signature PRIMREAL = sig
21: val significant : int
22: val outofrange : string -> unit
23: val emitreal : (int * bool array * int) -> unit
24: end
25:
26: signature REALCONST = sig
27: val realconst : string -> unit
28: end
29:
30: functor RealConst(P : PRIMREAL) : REALCONST =
31: struct
32:
33: open P
34:
35: (* Use more than the required precision, then round at the end. Because
36: bigints are signed, this is actually one bit less precision than you might
37: think. This criterion works well enough for the 53 bits required by
38: Vax G format and IEEE double format, but has not been tested with other
39: values of significant. *)
40: val precision = significant + 16 - ((significant + 8) mod 8)
41:
42: (* A float is a WHOLE "fraction" and an exponent base TWO. *)
43: type float = {frac : Bigint.bigint, exp : int}
44:
45: val bigint = Bigint.bigint
46: val plus = Bigint.+
47: val times = Bigint.*
48: infix plus times
49:
50: (* Take a bigint and return a bool array of bits which will represent the
51: fraction. The high (1/2) bit is in array position 0. Assumes that
52: the bigint is positive. This will work if the bigint is smaller than
53: the array or vice versa; however, the number will be truncated, not
54: rounded. *)
55: fun makebits (f,n) =
56: let val s = Bigint.size f
57: val bits = array(n,false)
58: fun onebit b = Bigint.getbit(f,s-1-b)
59: fun copybit n = (update(bits,n,onebit n); copybit (n+1))
60: handle Subscript => ()
61: in copybit 0;
62: bits
63: end
64:
65: (* round a float to n significant digits *)
66: local val one = bigint 1 in
67: fun round (float as {frac=f,exp=e},n) =
68: let val shift = Bigint.size f + 1 - n
69: in
70: if shift <= 0 then float
71: else {frac = if Bigint.getbit(f,shift-1)
72: then Bigint.>>(f, shift) plus one
73: else Bigint.>>(f, shift),
74: exp = e + shift}
75: end
76: end
77:
78: (* maketenth: create the float of one tenth, to any number of significant
79: digits, with no rounding on the last digit. *)
80: local val zero = bigint 0 and one = bigint 1 and two = bigint 2 in
81: fun maketenth 1 = {frac=one,exp= ~4}
82: | maketenth n =
83: let val {frac,exp} = maketenth(n-1)
84: val rec tenthbit = fn 0 => zero | 1 => one
85: | 2 => one | 3 => zero | n => tenthbit(n mod 4)
86: val f = (frac times two) plus tenthbit n
87: val e = exp - 1
88: in
89: {frac=f,exp=e}
90: end
91: end
92:
93: (* float values ten and one tenth, to the correct precision. *)
94: val ten = {frac=bigint 5, exp = 1}
95: val tenth = round(maketenth(precision+1),precision)
96:
97: (* Multiplies two floats together to the correct precision *)
98: fun mult {frac=f1,exp=e1} {frac=f2,exp=e2} =
99: let val f = f1 times f2
100: val e : int = e1 + e2
101: (* shouldn't need the type constraint, our comp bug *)
102: in
103: round({frac=f,exp=e},precision)
104: end
105:
106: (* Create a dynamic array of powers of ten *)
107: structure DFA = Dynamic(struct open Array
108: type float = {frac : Bigint.bigint, exp : int}
109: type elem = unit->float
110: type array = elem array
111: end)
112: local open DFA
113: exception Unknown
114: fun makelem e = (fn () => e)
115: val one = {frac=bigint 1,exp=0}
116: in
117: val pos10 = array(fn () => raise Unknown) (* 10^2^n *)
118: val _ = update(pos10,0,makelem ten)
119: val neg10 = array(fn () => raise Unknown) (* 10^~2^n *)
120: val _ = update(neg10,0,makelem tenth)
121: fun access(arr,n) = (arr sub n) ()
122: handle Unknown => let val last = access(arr,n-1)
123: val new = mult last last
124: in update(arr,n,makelem new);
125: new
126: end
127:
128: fun pow10_2 0 = one
129: | pow10_2 n = if n > 0 then access(pos10,n-1) else access(neg10,~n-1)
130: fun raisepower(f,0) = f
131: | raisepower(f,e) =
132: let val sign = if e<0 then ~1 else 1
133: fun power(f,p) = mult f (pow10_2(sign*p))
134: fun raisep(f,0,_) = f
135: | raisep(f,e,p) =
136: if Bits.andb(e,1) = 1 then raisep(power(f,p),Bits.rshift(e,1),p+1)
137: else raisep(f,Bits.rshift(e,1),p+1)
138: in raisep(f,abs e,1)
139: end
140: end
141:
142: (* Takes a string list of the form {digit*.[digit*]}, and returns a bigint and
143: the exponent base 10. Requires that the list contain a decimal point and
144: no trailing zeros (useless zeros after the decimal point). *)
145: local val ten = bigint 10 and zero = bigint 0 in
146: fun reducefrac f =
147: let fun getexp nil = 0
148: | getexp ("."::_) = 0
149: | getexp (_::tl) = getexp tl - 1
150: fun getwhole nil = zero
151: | getwhole ("."::tl) = getwhole tl
152: | getwhole ("0"::tl) = ten times getwhole tl
153: | getwhole (n::tl) = bigint(ord n - ord "0") plus (ten times getwhole tl)
154: val backwards = rev f
155: val whole = getwhole backwards
156: val exp = getexp backwards
157: in
158: (whole,exp)
159: end
160: end
161:
162: exception Toobig
163:
164: (* Takes a legal ML float string and returns an (int * bigint * int)
165: which is the sign, whole "fraction", and power of ten exponent *)
166: fun getparts s =
167: let datatype trailing = SIGNIFICANT | TRAILING
168: (* separate the fraction from the exponent, adding a decimal point if
169: there is none and eliminating trailing zeros *)
170: fun separate (nil,s) = (nil,nil,s)
171: | separate ("E"::tl,SIGNIFICANT) = (["."],tl,SIGNIFICANT)
172: | separate ("E"::tl,TRAILING) = (nil,tl,TRAILING)
173: | separate ("0"::tl,s) =
174: let val (r,e,s) = separate(tl,s)
175: in case s of TRAILING => (r,e,TRAILING)
176: | SIGNIFICANT => ("0"::r,e,SIGNIFICANT)
177: end
178: | separate ("."::tl,_) =
179: let val (r,e,_) = separate(tl,TRAILING)
180: in ("."::r,e,SIGNIFICANT)
181: end
182: | separate (hd::tl,s) =
183: let val (r,e,_) = separate(tl,s)
184: in (hd::r,e,SIGNIFICANT)
185: end
186: val (unsigned,sign) = case explode s of "~"::more => (more,1)
187: | other => (other,0)
188: val (frac_s,exp_s,_) = separate(unsigned,SIGNIFICANT)
189: fun atoi strlist =
190: let val numlist = map (fn n => ord n - ord "0") strlist
191: in List.revfold (fn (a:int,b) => b*10 + a) numlist 0
192: end
193: val exp10 = (case exp_s of nil => 0
194: | "~"::more => ~(atoi more)
195: | other => atoi other)
196: handle Overflow => raise Toobig
197: val (frac,exp) = reducefrac frac_s
198: in
199: (sign,frac,exp10 + exp)
200: end
201:
202: (* Takes a legal ML float string and returns an (int * bool array * int)
203: which is the sign, fraction (with the high(1/2) bit in array posn 0),
204: and exponent. This is the form expected by the functor parameter
205: emitreal. *)
206: fun makereal f =
207: let val (sign,frac10,exp10) = getparts f
208: val float = raisepower(round({frac=frac10,exp=0},precision),exp10)
209: val (newf as {frac,exp}) = round(float,significant+1)
210: val size = Bigint.size frac
211: val bits = makebits(frac,significant)
212: in
213: case size of 0 => (0,bits,0)
214: | _ => (sign,bits,exp + size)
215: end
216:
217: fun realconst f = emitreal(makereal f)
218: handle Toobig => (outofrange f; emitreal(makereal "0.0"))
219:
220: end (* functor RealConst *)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.