git.iko.soy/rowtype-yoga/purescript-fixed-precision
on main help sign in
Re-add EuclideanRing instance (#20)
b8d0a29Harry Garrood
generated-docs/Data/Fixed.mddeleted−398
@@ -1,398 +0,0 @@
1−## Module Data.Fixed
2−
3−This module defines a numeric type `Fixed` for working with
4−fixed point numbers in base 10. The precision is tracked in
5−the types.
6−
7−#### `Fixed`
8−
9−``` purescript
10−newtype Fixed (precision :: Precision)
11−```
12−
13−A fixed point representation of a real number, with the specified precision.
14−
15−A value is multiplied by the precision, truncated and stored as a big
16−integer. That is, we approximate the number by numerator/10^precision, storing
17−only the numerator, and carrying the precision around as type information.
18−
19−The `Semiring` and associated instances allow us to perform basic arithmetic
20−operations.
21−
22−##### Instances
23−``` purescript
24−(KnownPrecision precision) => Show (Fixed precision)
25−Eq (Fixed precision)
26−Ord (Fixed precision)
27−(KnownPrecision precision) => Semiring (Fixed precision)
28−(KnownPrecision precision) => Ring (Fixed precision)
29−(KnownPrecision precision) => CommutativeRing (Fixed precision)
30−```
31−
32−#### `fromInt`
33−
34−``` purescript
35−fromInt :: forall precision. KnownPrecision precision => Int -> Fixed precision
36−```
37−
38−Create a `Fixed` representation of an `Int`.
39−
40−#### `fromNumber`
41−
42−``` purescript
43−fromNumber :: forall precision. KnownPrecision precision => Number -> Maybe (Fixed precision)
44−```
45−
46−Approximate a `Number` as a `Fixed` value with the specified precision.
47−
48−```
49−> fromNumber 0.1234 :: Maybe (Fixed P10000)
50−(Just (fromNumber 0.1234 :: P10000))
51−
52−> fromNumber 0.1234 :: Maybe (Fixed P100)
53−(Just (fromNumber 0.12 :: P100))
54−```
55−
56−When given a finite `Number`, this function always succeeds: the number is
57−truncated (rounded towards zero) to the closest possible `Fixed` value.
58−This function only returns `Nothing` if it is given NaN, or positive or
59−negative infinity.
60−
61−```
62−> fromNumber (1.0 / 0.0) :: Maybe (Fixed P100)
63−Nothing
64−```
65−
66−#### `toNumber`
67−
68−``` purescript
69−toNumber :: forall precision. KnownPrecision precision => Fixed precision -> Number
70−```
71−
72−Convert a `Fixed` value to a `Number`.
73−
74−_Note_: Overflow is possible here if the numerator is sufficiently large.
75−Consider using `toString` instead.
76−
77−#### `fromString`
78−
79−``` purescript
80−fromString :: forall precision. KnownPrecision precision => String -> Maybe (Fixed precision)
81−```
82−
83−Parse a fixed-precision number from a string. Any decimal digits which are
84−not representable in the specified precision will be ignored.
85−
86−```
87−> fromString "123.456" :: Maybe (Fixed P1000)
88−(Just (fromString "123.456" :: P1000))
89−```
90−
91−Where possible, this function should be preferred over `fromNumber`, since
92−it is exact (whereas `fromNumber` can only provide an approximation for
93−larger inputs).
94−
95−```
96−> fromString "9007199254740992.5" :: Maybe (Fixed P10)
97−(Just (fromString "9007199254740992.5" :: P10))
98−
99−> fromNumber 9007199254740992.5 :: Maybe (Fixed P10)
100−(Just (fromString "9007199254740992.0" :: P10))
101−```
102−
103−
104−#### `toString`
105−
106−``` purescript
107−toString :: forall precision. KnownPrecision precision => Fixed precision -> String
108−```
109−
110−Represent a `Fixed` value as a string, using all of the decimal places it
111−can represent (based on its precision).
112−
113−```
114−> map toString (fromString "100.5" :: Maybe (Fixed P10))
115−(Just "100.5")
116−
117−> map toString (fromString "100.5" :: Maybe (Fixed P100))
118−(Just "100.50")
119−```
120−
121−#### `toStringWithPrecision`
122−
123−``` purescript
124−toStringWithPrecision :: forall precision. KnownPrecision precision => Int -> Fixed precision -> String
125−```
126−
127−Represent a `Fixed` value as a string, with the given number of decimal
128−places.
129−
130−```
131−> map (toStringWithPrecision 2) (fromString "1234.567" :: Maybe (Fixed P1000))
132−(Just "1234.56")
133−```
134−
135−If more decimal places are asked for than the type can provide, the extra
136−decimal places will be provided as zeroes.
137−
138−```
139−> map (toStringWithPrecision 3) (fromString "1234.5" :: Maybe (Fixed P10))
140−(Just "1234.500")
141−```
142−
143−#### `numerator`
144−
145−``` purescript
146−numerator :: forall precision. Fixed precision -> BigInt
147−```
148−
149−Extract the numerator from the representation of the number as a fraction.
150−
151−```
152−> map numerator (fromNumber 0.1234 :: Fixed P1000)
153−(Just fromString "123")
154−
155−> map numerator (fromNumber 0.1239 :: Fixed P1000)
156−(Just fromString "123")
157−```
158−
159−#### `floor`
160−
161−``` purescript
162−floor :: forall precision. KnownPrecision precision => Fixed precision -> Fixed precision
163−```
164−
165−Calculate the largest whole number smaller than or equal to the provided
166−value.
167−
168−```
169−> map floor $ fromNumber 0.1 :: Maybe (Fixed P10)
170−(Just (fromNumber 0.0 :: P10))
171−
172−> map floor $ fromNumber 1.0 :: Maybe (Fixed P10)
173−(Just (fromNumber 1.0 :: P10))
174−
175−> floor $ fromNumber (-0.1) :: Maybe (Fixed P10)
176−(Just (fromNumber (-1.0) :: P10))
177−```
178−
179−#### `ceil`
180−
181−``` purescript
182−ceil :: forall precision. KnownPrecision precision => Fixed precision -> Fixed precision
183−```
184−
185−Calculate the smallest whole number greater than or equal to the provided
186−value.
187−
188−```
189−> map ceil $ fromNumber 0.1 :: Maybe (Fixed P10)
190−(Just (fromNumber 1.0 :: P10))
191−
192−> map ceil $ fromNumber 1.0 :: Maybe (Fixed P10)
193−(Just (fromNumber 1.0 :: P10))
194−
195−> map ceil $ fromNumber (-0.1) :: Maybe (Fixed P10)
196−(Just (fromNumber 0.0 :: P10))
197−```
198−
199−#### `round`
200−
201−``` purescript
202−round :: forall precision. KnownPrecision precision => Fixed precision -> Fixed precision
203−```
204−
205−Round the specified value to the nearest whole number.
206−
207−```
208−> map round $ fromNumber 0.1 :: Maybe (Fixed P10)
209−(Just (fromNumber 0.0 :: P10))
210−
211−> map round $ fromNumber 0.9 :: Maybe (Fixed P10)
212−(Just (fromNumber 1.0 :: P10))
213−
214−> map round $ fromNumber 0.5 :: Maybe (Fixed P10)
215−(Just (fromNumber 1.0 :: P10))
216−
217−> map round $ fromNumber (-0.1) :: Maybe (Fixed P10)
218−(Just (fromNumber 0.0 :: P10))
219−```
220−
221−#### `approxDiv`
222−
223−``` purescript
224−approxDiv :: forall precision. KnownPrecision precision => Fixed precision -> Fixed precision -> Fixed precision
225−```
226−
227−Approximate division of fixed-precision numbers.
228−
229−```
230−> lift2 approxDiv (fromNumber 22.0) (fromNumber 7.0) :: Maybe (Fixed P100)
231−(Just (fromNumber 3.14 :: P100))
232−```
233−
234−_Note_: `Fixed` is not a `EuclideanRing` in general - it is not even
235−an integral domain, since it has non-zero zero-divisors:
236−
237−```
238−> lift2 (*) (fromNumber 0.1) (fromNumber 0.1) :: Maybe (Fixed P10)
239−(Just (fromNumber 0.0 :: P10))
240−```
241−
242−#### `Precision`
243−
244−``` purescript
245−kind Precision
246−```
247−
248−A kind for type-level precision information
249−
250−#### `One`
251−
252−``` purescript
253−data One :: Precision
254−```
255−
256−No decimal places
257−
258−##### Instances
259−``` purescript
260−KnownPrecision One
261−```
262−
263−#### `TenTimes`
264−
265−``` purescript
266−data TenTimes :: Precision -> Precision
267−```
268−
269−One more decimal place
270−
271−##### Instances
272−``` purescript
273−(KnownPrecision p) => KnownPrecision (TenTimes p)
274−```
275−
276−#### `P1`
277−
278−``` purescript
279−type P1 = One
280−```
281−
282−#### `P10`
283−
284−``` purescript
285−type P10 = TenTimes P1
286−```
287−
288−One decimal place
289−
290−#### `P100`
291−
292−``` purescript
293−type P100 = TenTimes P10
294−```
295−
296−Two decimal places
297−
298−#### `P1000`
299−
300−``` purescript
301−type P1000 = TenTimes P100
302−```
303−
304−Three decimal places
305−
306−#### `P10000`
307−
308−``` purescript
309−type P10000 = TenTimes P1000
310−```
311−
312−Four decimal places
313−
314−#### `P100000`
315−
316−``` purescript
317−type P100000 = TenTimes P10000
318−```
319−
320−Five decimal places
321−
322−#### `P1000000`
323−
324−``` purescript
325−type P1000000 = TenTimes P100000
326−```
327−
328−Six decimal places
329−
330−#### `PProxy`
331−
332−``` purescript
333−data PProxy (precision :: Precision)
334− = PProxy
335−```
336−
337−A value-level proxy for a type-level precision.
338−
339−#### `KnownPrecision`
340−
341−``` purescript
342−class KnownPrecision (precision :: Precision) where
343− reflectPrecision :: PProxy precision -> BigInt
344−```
345−
346−Precision which is known, i.e. it can be reflected to a
347−value at runtime, given a `PProxy`.
348−
349−`reflectPrecision` returns a multiple of ten, corresponding
350−to the maximum number of decimal places which can be stored.
351−
352−```
353−> reflectPrecision (PProxy :: PProxy P1000)
354−1000
355−```
356−
357−##### Instances
358−``` purescript
359−KnownPrecision One
360−(KnownPrecision p) => KnownPrecision (TenTimes p)
361−```
362−
363−#### `reflectPrecisionDecimalPlaces`
364−
365−``` purescript
366−reflectPrecisionDecimalPlaces :: forall precision. KnownPrecision precision => PProxy precision -> Int
367−```
368−
369−Get the number of decimal places associated with a given `Precision` at
370−the value level.
371−
372−```
373−> reflectPrecisionDecimalPlaces (PProxy :: PProxy P1000)
374−3
375−```
376−
377−#### `reifyPrecision`
378−
379−``` purescript
380−reifyPrecision :: forall r. Int -> (forall precision. KnownPrecision precision => PProxy precision -> r) -> Maybe r
381−```
382−
383−Reify an non-negative integer (a power of ten) as a `Precision`.
384−
385−For example
386−
387−```
388−> reifyPrecision 0 reflectPrecision
389−Just 1
390−> reifyPrecision 1 reflectPrecision
391−Just 10
392−> reifyPrecision 2 reflectPrecision
393−Just 100
394−> reifyPrecision (-1) reflectPrecision
395−Nothing
396−```
397−
398−
src/Data/Fixed.purs+23−21
@@ -43,6 +43,7 @@ import Data.Monoid as Monoid
43import Data.String.CodeUnits as StringCU
43import Data.String.CodeUnits as StringCU
44import Data.String as String
44import Data.String as String
45import Math as Math
45import Math as Math
46+import Prim.TypeError (class Warn, Text)
46
47
47-- | A kind for type-level precision information
48-- | A kind for type-level precision information
48foreign import kind Precision
49foreign import kind Precision
@@ -141,7 +142,10 @@ reifyPrecision n f = reifyPrecision (n - 1) (f <<< liftTenTimes) where
141-- | only the numerator, and carrying the precision around as type information.
142-- | only the numerator, and carrying the precision around as type information.
142-- |
143-- |
143-- | The `Semiring` and associated instances allow us to perform basic arithmetic
144-- | The `Semiring` and associated instances allow us to perform basic arithmetic
144−-- | operations.
145+-- | operations. Unlike `Number`, addition of `Fixed` numbers does satisfy the
146+-- | associativity law, but like `Number`, most of the other laws of the
147+-- | numeric hierarchy classes are not satisfied due to rounding errors.
148+-- |
145newtype Fixed (precision :: Precision) = Fixed BigInt.BigInt
149newtype Fixed (precision :: Precision) = Fixed BigInt.BigInt
146
150
147-- | Extract the numerator from the representation of the number as a fraction.
151-- | Extract the numerator from the representation of the number as a fraction.
@@ -280,31 +284,16 @@ round n = Fixed (numerator n + x) where
280 | m * BigInt.fromInt 2 >= d = d - m
284 | m * BigInt.fromInt 2 >= d = d - m
281 | otherwise = -m
285 | otherwise = -m
282
286
283−-- | Approximate division of fixed-precision numbers.
287+-- | Division of fixed-precision numbers. This function is deprecated; you
284−-- |
288+-- | should use `/` from the `EuclideanRing` instance instead.
285−-- | ```
286−-- | > lift2 approxDiv (fromNumber 22.0) (fromNumber 7.0) :: Maybe (Fixed P100)
287−-- | (Just (fromNumber 3.14 :: P100))
288−-- | ```
289−-- |
290−-- | _Note_: `Fixed` is not a `EuclideanRing` in general - it is not even
291−-- | an integral domain, since it has non-zero zero-divisors:
292−-- |
293−-- | ```
294−-- | > lift2 (*) (fromNumber 0.1) (fromNumber 0.1) :: Maybe (Fixed P10)
295−-- | (Just (fromNumber 0.0 :: P10))
296−-- | ```
297approxDiv
289approxDiv
298 :: forall precision
290 :: forall precision
291+ . Warn (Text "This function is deprecated, please use `/` instead")
299− . KnownPrecision precision
292+ => KnownPrecision precision
300 => Fixed precision
293 => Fixed precision
301 -> Fixed precision
294 -> Fixed precision
302 -> Fixed precision
295 -> Fixed precision
303−approxDiv a b = Fixed (x * n / y)
296+approxDiv = div
304− where
305− x = numerator a
306− y = numerator b
307− n = denominator a
308
297
309-- | Parse a fixed-precision number from a string. Any decimal digits which are
298-- | Parse a fixed-precision number from a string. Any decimal digits which are
310-- | not representable in the specified precision will be ignored.
299-- | not representable in the specified precision will be ignored.
@@ -455,3 +444,16 @@ instance ringFixed :: KnownPrecision precision => Ring (Fixed precision) where
455 sub (Fixed n) (Fixed m) = Fixed (n - m)
444 sub (Fixed n) (Fixed m) = Fixed (n - m)
456
445
457instance commutativeRingFixed :: KnownPrecision precision => CommutativeRing (Fixed precision)
446instance commutativeRingFixed :: KnownPrecision precision => CommutativeRing (Fixed precision)
447+
448+instance euclideanRingFixed :: KnownPrecision precision => EuclideanRing (Fixed precision) where
449+ degree = const 1
450+ mod _ _ = zero
451+ div a b =
452+ Fixed (x * n / y)
453+ where
454+ x = numerator a
455+ y = numerator b
456+ n = denominator a
457+
458+instance divisionRingFixed :: KnownPrecision precision => DivisionRing (Fixed precision) where
459+ recip x = one / x