Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Annotation of /trunk/src/common/float-lit.sml
ViewVC logotype

Annotation of /trunk/src/common/float-lit.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (view) (download)

1 : jhr 26 (* float-lit.sml
2 :     *
3 :     * COPYRIGHT (c) 2010 The Diderot Project (http://diderot.cs.uchicago.edu)
4 :     * All rights reserved.
5 :     *
6 :     * Internal representation of floating-point literals with limited
7 :     * support for arithmetic.
8 :     *)
9 :    
10 :     structure FloatLit :> sig
11 :    
12 :     type float
13 :    
14 :     val isZero : float -> bool
15 :    
16 :     (* return the representation of +/-0.0 *)
17 :     val zero : bool ->float
18 :    
19 :     (* plus and minus one *)
20 :     val one : float
21 :     val m_one : float
22 :    
23 :     (* negate a float *)
24 :     val negate : float -> float
25 :    
26 :     (* equality, comparisons, and hashing functions *)
27 :     val same : (float * float) -> bool
28 :     val compare : (float * float) -> order
29 :     val hash : float -> word
30 :    
31 :     (* create a float from pieces: isNeg is true if the number is negative, whole
32 :     * is the whole-number part, frac is the fractional part, and exp is the
33 :     * exponent. This function may raise Overflow, when the exponent of the
34 :     * normalized representation is too small or too large.
35 :     *)
36 :     val float : {isNeg : bool, whole : string, frac : string, exp : int} -> float
37 :     val toString : float -> string
38 :    
39 :     (* external representation (for pickling) *)
40 :     val toBytes : float -> Word8Vector.vector
41 :     val fromBytes : Word8Vector.vector -> float
42 :    
43 :     end = struct
44 :    
45 :     structure SS = Substring
46 :     structure W = Word
47 :     structure W8V = Word8Vector
48 :    
49 :     (* The value {isNeg, digits=[d0, ..., dn], exp} represents the number
50 :     *
51 :     * [+/-] 0.d0...dn * 10^exp
52 :     *
53 :     * where the sign is negative if isNeg is true.
54 :     *)
55 :     type float = {isNeg : bool, digits : int list, exp : int}
56 :    
57 :     fun isZero {isNeg, digits=[0], exp} = true
58 :     | isZero _ = false
59 :    
60 :     fun zero isNeg = {isNeg = isNeg, digits = [0], exp = 0}
61 :    
62 :     val one = {isNeg = false, digits = [1], exp = 1}
63 :     val m_one = {isNeg = true, digits = [1], exp = 1}
64 :    
65 :     (* negate a float *)
66 :     fun negate {isNeg, digits, exp} =
67 :     {isNeg = not isNeg, digits = digits, exp = exp}
68 :    
69 :     (* equality, comparisons, and hashing functions *)
70 :     fun same (f1 : float, f2 : float) =
71 :     (#isNeg f1 = #isNeg f2) andalso (#exp f1 = #exp f2)
72 :     andalso (#digits f1 = #digits f2)
73 :    
74 :     fun compare (f1 : float, f2 : float) = (case (#isNeg f1, #isNeg f2)
75 :     of (false, true) => GREATER
76 :     | (true, false) => LESS
77 :     | _ => (case Int.compare(#exp f1, #exp f2)
78 :     of EQUAL => let
79 :     fun cmp ([], []) = EQUAL
80 :     | cmp ([], _) = LESS
81 :     | cmp (_, []) = GREATER
82 :     | cmp (d1::r1, d2::r2) = (case Int.compare(d1, d2)
83 :     of EQUAL => cmp(r1, r2)
84 :     | order => order
85 :     (* end case *))
86 :     in
87 :     cmp (#digits f1, #digits f2)
88 :     end
89 :     | order => order
90 :     (* end case *))
91 :     (* end case *))
92 :    
93 :     fun hash {isNeg, digits, exp} = let
94 :     fun hashDigits ([], h, _) = h
95 :     | hashDigits (d::r, h, i) =
96 :     hashDigits (r, W.<<(W.fromInt d, i+0w4), W.andb(i+0w1, 0wxf))
97 :     in
98 :     hashDigits(digits, W.fromInt exp, 0w0)
99 :     end
100 :    
101 :     fun float {isNeg, whole, frac, exp} = let
102 :     fun cvtDigit (c, l) = (Char.ord c - Char.ord #"0") :: l
103 :     fun isZero #"0" = true | isZero _ = false
104 :     (* whole digits with leading zeros removed *)
105 :     val whole = SS.dropl isZero (SS.full whole)
106 :     (* fractional digits with trailing zeros removed *)
107 :     val frac = SS.dropr isZero (SS.full frac)
108 :     (* normalize by stripping leading zero digits *)
109 :     fun normalize {isNeg, digits=[], exp} = zero isNeg
110 :     | normalize {isNeg, digits=0::r, exp} =
111 :     normalize {isNeg=isNeg, digits=r, exp=exp-1}
112 :     | normalize flt = flt
113 :     in
114 :     case SS.foldr cvtDigit (SS.foldr cvtDigit [] frac) whole
115 :     of [] => zero isNeg
116 :     | digits => normalize {
117 :     isNeg = isNeg,
118 :     digits = digits,
119 :     exp = exp + SS.size whole
120 :     }
121 :     (* end case *)
122 :     end
123 :    
124 :     fun toString {isNeg, digits, exp} = let
125 :     val s = if isNeg then "-0." else "0."
126 :     val e = if exp < 0
127 :     then ["e-", Int.toString(~exp)]
128 :     else ["e", Int.toString exp]
129 :     in
130 :     concat(s :: List.foldr (fn (d, ds) => Int.toString d :: ds) e digits)
131 :     end
132 :    
133 :    
134 :    
135 :     (***** external representation (for pickling) *****
136 :     *
137 :     * The representation we use is a sequence of bytes:
138 :     *
139 :     * [sign, d0, ..., dn, exp0, ..., exp3]
140 :     *
141 :     * where
142 :     * sign == 0 or 1
143 :     * di == ith digit
144 :     * expi == ith byte of exponent (exp0 is lsb, exp3 is msb).
145 :     *
146 :     * NOTE: we could pack the sign and digits into 4-bit nibbles, but we are keeping
147 :     * things simple for now.
148 :     *)
149 :    
150 :     fun toBytes {isNeg, digits, exp} = let
151 :     val sign = if isNeg then 0w1 else 0w0
152 :     val digits = List.map Word8.fromInt digits
153 :     val exp' = W.fromInt exp
154 :     fun byte i = Word8.fromLargeWord(W.toLargeWord((W.>>(exp', 0w8*i))))
155 :     val exp = [byte 0w0, byte 0w1, byte 0w2, byte 0w3]
156 :     in
157 :     Word8Vector.fromList(sign :: (digits @ exp))
158 :     end
159 :    
160 :     fun fromBytes v = let
161 :     val ndigits = W8V.length v - 5
162 :     fun error () = raise Fail "Bogus float pickle"
163 :     val _ = if (ndigits < 1) then error() else ()
164 :     val isNeg = (case W8V.sub(v, 0)
165 :     of 0w0 => false
166 :     | 0w1 => true
167 :     | _ => error()
168 :     (* end case *))
169 :     fun digit i = Word8.toInt(W8V.sub(v, i+1))
170 :     fun byte i = W.<<(
171 :     W.fromLargeWord(Word8.toLargeWord(W8V.sub(v, ndigits+1+i))),
172 :     W.fromInt(8*i))
173 :     val exp = W.toIntX(W.orb(byte 3, W.orb(byte 2, W.orb(byte 1, byte 0))))
174 :     in
175 :     {isNeg = isNeg, digits = List.tabulate(ndigits, digit), exp = exp}
176 :     end
177 :    
178 :     end
179 :    

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0