|
1 structure ExactFloatingPoint : |
|
2 sig |
|
3 exception Destruct_floatstr of string |
|
4 |
|
5 val destruct_floatstr : (char -> bool) -> (char -> bool) -> string -> bool * string * string * bool * string |
|
6 |
|
7 exception Floating_point of string |
|
8 |
|
9 type floatrep = IntInf.int * IntInf.int |
|
10 val approx_dec_by_bin : IntInf.int -> floatrep -> floatrep * floatrep |
|
11 val approx_decstr_by_bin : int -> string -> floatrep * floatrep |
|
12 end |
|
13 = |
|
14 struct |
|
15 |
|
16 fun fst (a,b) = a |
|
17 fun snd (a,b) = b |
|
18 |
|
19 val filter = List.filter; |
|
20 |
|
21 exception Destruct_floatstr of string; |
|
22 |
|
23 fun destruct_floatstr isDigit isExp number = |
|
24 let |
|
25 val numlist = filter (not o Char.isSpace) (String.explode number) |
|
26 |
|
27 fun countsigns ((#"+")::cs) = countsigns cs |
|
28 | countsigns ((#"-")::cs) = |
|
29 let |
|
30 val (positive, rest) = countsigns cs |
|
31 in |
|
32 (not positive, rest) |
|
33 end |
|
34 | countsigns cs = (true, cs) |
|
35 |
|
36 fun readdigits [] = ([], []) |
|
37 | readdigits (q as c::cs) = |
|
38 if (isDigit c) then |
|
39 let |
|
40 val (digits, rest) = readdigits cs |
|
41 in |
|
42 (c::digits, rest) |
|
43 end |
|
44 else |
|
45 ([], q) |
|
46 |
|
47 fun readfromexp_helper cs = |
|
48 let |
|
49 val (positive, rest) = countsigns cs |
|
50 val (digits, rest') = readdigits rest |
|
51 in |
|
52 case rest' of |
|
53 [] => (positive, digits) |
|
54 | _ => raise (Destruct_floatstr number) |
|
55 end |
|
56 |
|
57 fun readfromexp [] = (true, []) |
|
58 | readfromexp (c::cs) = |
|
59 if isExp c then |
|
60 readfromexp_helper cs |
|
61 else |
|
62 raise (Destruct_floatstr number) |
|
63 |
|
64 fun readfromdot [] = ([], readfromexp []) |
|
65 | readfromdot ((#".")::cs) = |
|
66 let |
|
67 val (digits, rest) = readdigits cs |
|
68 val exp = readfromexp rest |
|
69 in |
|
70 (digits, exp) |
|
71 end |
|
72 | readfromdot cs = readfromdot ((#".")::cs) |
|
73 |
|
74 val (positive, numlist) = countsigns numlist |
|
75 val (digits1, numlist) = readdigits numlist |
|
76 val (digits2, exp) = readfromdot numlist |
|
77 in |
|
78 (positive, String.implode digits1, String.implode digits2, fst exp, String.implode (snd exp)) |
|
79 end |
|
80 |
|
81 type floatrep = IntInf.int * IntInf.int |
|
82 |
|
83 exception Floating_point of string; |
|
84 |
|
85 val ln2_10 = (Math.ln 10.0)/(Math.ln 2.0) |
|
86 |
|
87 fun intmul a b = IntInf.* (a,b) |
|
88 fun intsub a b = IntInf.- (a,b) |
|
89 fun intadd a b = IntInf.+ (a,b) |
|
90 fun intpow a b = IntInf.pow (a, IntInf.toInt b); |
|
91 fun intle a b = IntInf.<= (a, b); |
|
92 fun intless a b = IntInf.< (a, b); |
|
93 fun intneg a = IntInf.~ a; |
|
94 val zero = IntInf.fromInt 0; |
|
95 val one = IntInf.fromInt 1; |
|
96 val two = IntInf.fromInt 2; |
|
97 val ten = IntInf.fromInt 10; |
|
98 val five = IntInf.fromInt 5; |
|
99 |
|
100 fun find_most_significant q r = |
|
101 let |
|
102 fun int2real i = |
|
103 case Real.fromString (IntInf.toString i) of |
|
104 SOME r => r |
|
105 | NONE => raise (Floating_point "int2real") |
|
106 fun subtract (q, r) (q', r') = |
|
107 if intle r r' then |
|
108 (intsub q (intmul q' (intpow ten (intsub r' r))), r) |
|
109 else |
|
110 (intsub (intmul q (intpow ten (intsub r r'))) q', r') |
|
111 fun bin2dec d = |
|
112 if intle zero d then |
|
113 (intpow two d, zero) |
|
114 else |
|
115 (intpow five (intneg d), d) |
|
116 |
|
117 val L = IntInf.fromInt (Real.floor (int2real (IntInf.fromInt (IntInf.log2 q)) + (int2real r) * ln2_10)) |
|
118 val L1 = intadd L one |
|
119 |
|
120 val (q1, r1) = subtract (q, r) (bin2dec L1) |
|
121 in |
|
122 if intle zero q1 then |
|
123 let |
|
124 val (q2, r2) = subtract (q, r) (bin2dec (intadd L1 one)) |
|
125 in |
|
126 if intle zero q2 then |
|
127 raise (Floating_point "find_most_significant") |
|
128 else |
|
129 (L1, (q1, r1)) |
|
130 end |
|
131 else |
|
132 let |
|
133 val (q0, r0) = subtract (q, r) (bin2dec L) |
|
134 in |
|
135 if intle zero q0 then |
|
136 (L, (q0, r0)) |
|
137 else |
|
138 raise (Floating_point "find_most_significant") |
|
139 end |
|
140 end |
|
141 |
|
142 fun approx_dec_by_bin n (q,r) = |
|
143 let |
|
144 fun addseq acc d' [] = acc |
|
145 | addseq acc d' (d::ds) = addseq (intadd acc (intpow two (intsub d d'))) d' ds |
|
146 |
|
147 fun seq2bin [] = (zero, zero) |
|
148 | seq2bin (d::ds) = (intadd (addseq zero d ds) one, d) |
|
149 |
|
150 fun approx d_seq d0 precision (q,r) = |
|
151 if q = zero then |
|
152 let val x = seq2bin d_seq in |
|
153 (x, x) |
|
154 end |
|
155 else |
|
156 let |
|
157 val (d, (q', r')) = find_most_significant q r |
|
158 in |
|
159 if intless precision (intsub d0 d) then |
|
160 let |
|
161 val d' = intsub d0 precision |
|
162 val x1 = seq2bin (d_seq) |
|
163 val x2 = (intadd (intmul (fst x1) (intpow two (intsub (snd x1) d'))) one, d') (* = seq2bin (d'::d_seq) *) |
|
164 in |
|
165 (x1, x2) |
|
166 end |
|
167 else |
|
168 approx (d::d_seq) d0 precision (q', r') |
|
169 end |
|
170 |
|
171 fun approx_start precision (q, r) = |
|
172 if q = zero then |
|
173 ((zero, zero), (zero, zero)) |
|
174 else |
|
175 let |
|
176 val (d, (q', r')) = find_most_significant q r |
|
177 in |
|
178 if intle precision zero then |
|
179 let |
|
180 val x1 = seq2bin [d] |
|
181 in |
|
182 if q' = zero then |
|
183 (x1, x1) |
|
184 else |
|
185 (x1, seq2bin [intadd d one]) |
|
186 end |
|
187 else |
|
188 approx [d] d precision (q', r') |
|
189 end |
|
190 in |
|
191 if intle zero q then |
|
192 approx_start n (q,r) |
|
193 else |
|
194 let |
|
195 val ((a1,b1), (a2, b2)) = approx_start n (intneg q, r) |
|
196 in |
|
197 ((intneg a2, b2), (intneg a1, b1)) |
|
198 end |
|
199 end |
|
200 |
|
201 fun approx_decstr_by_bin n decstr = |
|
202 let |
|
203 fun str2int s = case IntInf.fromString s of SOME x => x | NONE => zero |
|
204 fun signint p x = if p then x else intneg x |
|
205 |
|
206 val (p, d1, d2, ep, e) = destruct_floatstr Char.isDigit (fn e => e = #"e" orelse e = #"E") decstr |
|
207 val s = IntInf.fromInt (size d2) |
|
208 |
|
209 val q = signint p (intadd (intmul (str2int d1) (intpow ten s)) (str2int d2)) |
|
210 val r = intsub (signint ep (str2int e)) s |
|
211 in |
|
212 approx_dec_by_bin (IntInf.fromInt n) (q,r) |
|
213 end |
|
214 |
|
215 end; |