0 | module Data.Fixed
  1 |
  2 | import Data.String
  3 |
  4 | %hide Data.List.replicate
  5 |
  6 | --------------------------------------------------------------------------------
  7 | --          Fixed
  8 | --------------------------------------------------------------------------------
  9 |
 10 | ||| The type of fixed-point fractional numbers.
 11 | public export
 12 | data Fixed : (res : Integer) -> Type where
 13 |   MkFixed :  Integer
 14 |           -> Fixed res
 15 |
 16 | --------------------------------------------------------------------------------
 17 | --          Show Utility
 18 | --------------------------------------------------------------------------------
 19 |
 20 | ||| Render a fixed-point value to a string, with optional trailing zero chopping.
 21 | |||
 22 | ||| @chop  whether to drop trailing zeros from the fractional part
 23 | ||| @fa    the fixed-point value, whose type index encodes resolution
 24 | private
 25 | showFixed :  {res : Integer}
 26 |           -> (chop : Bool)
 27 |           -> (fa : Fixed res)
 28 |           -> String
 29 | showFixed chop fa@(MkFixed a) =
 30 |   case a < 0 of
 31 |     True =>
 32 |       let fixed = assert_total $
 33 |                   showFixed {res}
 34 |                             chop
 35 |                             (MkFixed (negate a))
 36 |         in "-" ++ fixed
 37 |     False =>
 38 |       let (i, d)  = divMod a res
 39 |           digits  = cast {to=Int} (length (show res)) - 1
 40 |           maxnum  = pow 10 (cast {to=Double} digits)
 41 |           fracnum = divCeil (d * cast {to=Integer} maxnum) res
 42 |           dot     = withDot (showIntegerZeros chop (cast digits) fracnum)
 43 |        in show i ++ dot
 44 |   where
 45 |     sigNum :  Integer
 46 |            -> Integer
 47 |     sigNum n =
 48 |       case n < 0 of
 49 |         True  =>
 50 |           -1
 51 |         False =>
 52 |           case n == 0 of
 53 |             True  =>
 54 |               0
 55 |             False =>
 56 |               1
 57 |     divMod :  Integer
 58 |            -> Integer
 59 |            -> (Integer, Integer)
 60 |     divMod n d =
 61 |       let q = div n d
 62 |           r = mod n d
 63 |         in case sigNum r == negate (sigNum d) of
 64 |              True  =>
 65 |                (q - 1, r + d)
 66 |              False =>
 67 |                (q, r)
 68 |     chopZeros :  Integer
 69 |               -> String
 70 |     chopZeros 0 =
 71 |       ""
 72 |     chopZeros x =
 73 |       case mod x 10 == 0 of
 74 |         True  =>
 75 |           chopZeros (assert_smaller x (div x 10))
 76 |         False =>
 77 |           show x
 78 |     showIntegerZeros :  Bool
 79 |                      -> Nat
 80 |                      -> Integer
 81 |                      -> String
 82 |     showIntegerZeros True _      0 =
 83 |       ""
 84 |     showIntegerZeros chop digits n =
 85 |       let s       = show n
 86 |           s'      = case chop of
 87 |                       True  =>
 88 |                         chopZeros n
 89 |                       False =>
 90 |                         s
 91 |           padding = replicate (digits `minus` length s) '0'
 92 |         in padding ++ s'
 93 |     withDot :  String
 94 |             -> String
 95 |     withDot "" =
 96 |       ""
 97 |     withDot s  =
 98 |       "." ++ s
 99 |     divCeil :  Integer
100 |             -> Integer
101 |             -> Integer
102 |     divCeil x y =
103 |       (x + y - 1) `div` y
104 |
105 | --------------------------------------------------------------------------------
106 | --          Interfaces
107 | --------------------------------------------------------------------------------
108 |
109 | public export
110 | {n : Integer} -> Num (Fixed n) where
111 |   (MkFixed a) + (MkFixed b) = MkFixed (a + b)
112 |   (MkFixed a) * (MkFixed b) = MkFixed (div (a * b) n)
113 |   fromInteger i             = MkFixed (i * n)
114 |
115 | public export
116 | {n : Integer} -> Neg (Fixed n) where
117 |   negate (MkFixed a)          = MkFixed (negate a)
118 |   (-) (MkFixed a) (MkFixed b) = MkFixed (a - b)
119 |
120 | public export
121 | {n : Integer} -> Fractional (Fixed n) where
122 |   (MkFixed a) / (MkFixed b) = MkFixed (div (a * n) b)
123 |   recip (MkFixed a)         = MkFixed (div (n * n) a)
124 |
125 | public export
126 | {n : Integer} -> Eq (Fixed n) where
127 |   (MkFixed a) == (MkFixed b) = a == b
128 |
129 | public export
130 | {n : Integer} -> Ord (Fixed n) where
131 |   compare (MkFixed a) (MkFixed b) = compare a b
132 |
133 | public export
134 | {n : Integer} -> Show (Fixed n) where
135 |   showPrec p fixed@(MkFixed a) =
136 |     showParens (p >= App && a < 0) $
137 |       showFixed False fixed
138 |
139 | --------------------------------------------------------------------------------
140 | --          E0/Uni
141 | --------------------------------------------------------------------------------
142 |
143 | ||| +------------+---------------------+------+------------+
144 | ||| | Resolution | Scaling Factor      | Type | show 12345 |
145 | ||| +============+=====================+======+============+
146 | ||| | E0         | 1\1                 | Uni  | 12345.0    |
147 | ||| +------------+---------------------+------+------------+
148 | public export
149 | Uni : Type
150 | Uni = Fixed 1
151 |
152 | --------------------------------------------------------------------------------
153 | --          E1/Deci
154 | --------------------------------------------------------------------------------
155 |
156 | ||| +------------+---------------------+------+------------+
157 | ||| | Resolution | Scaling Factor      | Type | show 12345 |
158 | ||| +============+=====================+======+============+
159 | ||| | E1         | 1\10                | Deci | 1234.5     |
160 | ||| +------------+---------------------+------+------------+
161 | public export
162 | Deci : Type
163 | Deci = Fixed 10
164 |
165 | --------------------------------------------------------------------------------
166 | --          E2/Centi
167 | --------------------------------------------------------------------------------
168 |
169 | ||| +------------+---------------------+-------+------------+
170 | ||| | Resolution | Scaling Factor      | Type  | show 12345 |
171 | ||| +============+=====================+=======+============+
172 | ||| | E2         | 1\100               | Centi | 123.45     |
173 | ||| +------------+---------------------+-------+------------+
174 | public export
175 | Centi : Type
176 | Centi = Fixed 100
177 |
178 | --------------------------------------------------------------------------------
179 | --          E3/Milli
180 | --------------------------------------------------------------------------------
181 |
182 | ||| +------------+--------------------+-------+------------+
183 | ||| | Resolution | Scaling Factor     | Type  | show 12345 |
184 | ||| +============+====================+=======+============+
185 | ||| | E3         | 1\1000             | Milli | 12.345     |
186 | ||| +------------+--------------------+-------+------------+
187 | public export
188 | Milli : Type
189 | Milli = Fixed 1000
190 |
191 | --------------------------------------------------------------------------------
192 | --          E4/TenthMilli
193 | --------------------------------------------------------------------------------
194 |
195 | ||| +------------+--------------------+------------+------------+
196 | ||| | Resolution | Scaling Factor     | Type       | show 12345 |
197 | ||| +============+====================+=======+=================+
198 | ||| | E4         | 1\10000            | TenthMilli | 1.2345     |
199 | ||| +------------+--------------------+------------+------------+
200 | public export
201 | TenthMilli : Type
202 | TenthMilli = Fixed 10000
203 |
204 | --------------------------------------------------------------------------------
205 | --          E5/HundredthMilli
206 | --------------------------------------------------------------------------------
207 |
208 | ||| +------------+--------------------+------------------------+------------+
209 | ||| | Resolution | Scaling Factor     | Type                   | show 12345 |
210 | ||| +============+====================+========================+============+
211 | ||| | E5         | 1\100000           | HundredthMilli         | 0.12345    |
212 | ||| +------------+--------------------+------------------------+------------+
213 | public export
214 | HundredthMilli : Type
215 | HundredthMilli = Fixed 100000
216 |
217 | --------------------------------------------------------------------------------
218 | --          E6/Micro
219 | --------------------------------------------------------------------------------
220 |
221 | ||| +------------+-------------------+-------+------------+
222 | ||| | Resolution | Scaling Factor    | Type  | show 12345 |
223 | ||| +============+===================+=======+============+
224 | ||| | E6         | 1\1000000         | Micro | 0.012345   |
225 | ||| +------------+-------------------+-------+------------+
226 | public export
227 | Micro : Type
228 | Micro = Fixed 1000000
229 |
230 | --------------------------------------------------------------------------------
231 | --          E7/DeciMicro
232 | --------------------------------------------------------------------------------
233 |
234 | ||| +------------+-------------------+-----------+------------+
235 | ||| | Resolution | Scaling Factor    | Type      | show 12345 |
236 | ||| +============+===================+===========+============+
237 | ||| | E7         | 1\10000000        | DeciMicro | 0.0012345  |
238 | ||| +------------+-------------------+-----------+------------+
239 | public export
240 | DeciMicro : Type
241 | DeciMicro = Fixed 10000000
242 |
243 | --------------------------------------------------------------------------------
244 | --          E8/CentiMicro
245 | --------------------------------------------------------------------------------
246 |
247 | ||| +------------+--------------------+------------+------------+
248 | ||| | Resolution | Scaling Factor     | Type       | show 12345 |
249 | ||| +============+====================+============+============+
250 | ||| | E8         | 1\100000000        | CentiMicro | 0.00012345 |
251 | ||| +------------+--------------------+------------+------------+
252 | public export
253 | CentiMicro : Type
254 | CentiMicro = Fixed 100000000
255 |
256 | --------------------------------------------------------------------------------
257 | --          E9/Nano
258 | --------------------------------------------------------------------------------
259 |
260 | ||| +------------+------------------+------+-------------+
261 | ||| | Resolution | Scaling Factor   | Type | show 12345  |
262 | ||| +============+==================+======+=============+
263 | ||| | E9         | 1\1000000000     | Nano | 0.000012345 |
264 | ||| +------------+------------------+------+-------------+
265 | public export
266 | Nano : Type
267 | Nano = Fixed 1000000000
268 |
269 | --------------------------------------------------------------------------------
270 | --          E10/DeciNano
271 | --------------------------------------------------------------------------------
272 |
273 | ||| +------------+-----------------+----------+--------------+
274 | ||| | Resolution | Scaling Factor  | Type     | show 12345   |
275 | ||| +============+=================+==========+==============+
276 | ||| | E10        | 1\10000000000   | DeciNano | 0.0000012345 |
277 | ||| +------------+-----------------+----------+--------------+
278 | public export
279 | DeciNano : Type
280 | DeciNano = Fixed 10000000000
281 |
282 | --------------------------------------------------------------------------------
283 | --          E11/CentiNano
284 | --------------------------------------------------------------------------------
285 |
286 | ||| +------------+-----------------+-----------+---------------+
287 | ||| | Resolution | Scaling Factor  | Type      | show 12345    |
288 | ||| +============+=================+===========+===============+
289 | ||| | E11        | 1\100000000000  | CentiNano | 0.00000012345 |
290 | ||| +------------+-----------------+-----------+---------------+
291 | public export
292 | CentiNano : Type
293 | CentiNano = Fixed 100000000000
294 |
295 | --------------------------------------------------------------------------------
296 | --          E12/Pico
297 | --------------------------------------------------------------------------------
298 |
299 | ||| +------------+-----------------+------+----------------+
300 | ||| | Resolution | Scaling Factor  | Type | show 12345     |
301 | ||| +============+=================+======+================+
302 | ||| | E12        | 1\1000000000000 | Pico | 0.000000012345 |
303 | ||| +------------+-----------------+------+----------------+
304 | public export
305 | Pico : Type
306 | Pico = Fixed 1000000000000
307 |
308 | --------------------------------------------------------------------------------
309 | --          withResolution
310 | --------------------------------------------------------------------------------
311 |
312 | ||| Run a computation with the resolution available as an `Integer`.
313 | export
314 | withResolution :  {res : Integer}
315 |                -> (f : Integer -> b)
316 |                -> b
317 | withResolution f =
318 |   f res
319 |