git.iko.soy/rowtype-yoga/purescript-fixed-precision
on main help sign in
Add 'rescale' (#25)
commit623e5136f3eb9a92f002b79692c3fd55406b5086 authorHarry Garrood <harry@garrood.me> dateWed 4 Mar 2020, 21:22 (7 years ago) parentabd54d5
2 files changed+65−2
src/Data/Fixed.purs+14−1 test/Main.purs+51−1
src/Data/Fixed.purs+14−1
@@ -15,6 +15,7 @@ module Data.Fixed
1515 , floor
1616 , ceil
1717 , round
18+ , rescale
1819 , approxDiv
1920 , kind Precision
2021 , One
@@ -40,11 +41,12 @@ import Data.Array (replicate)
4041import Data.BigInt (BigInt)
4142import Data.BigInt as BigInt
4243import Data.Int as Int
43−import Data.Maybe (Maybe(..))
44+import Data.Maybe (Maybe(..), fromJust)
4445import Data.Monoid as Monoid
4546import Data.String.CodeUnits as StringCU
4647import Data.String as String
4748import Math as Math
49+import Partial.Unsafe (unsafePartial)
4850import Prim.TypeError (class Warn, Text)
4951
5052-- | A kind for type-level precision information
@@ -294,6 +296,17 @@ round n = Fixed (numerator n + x) where
294296 | m * BigInt.fromInt 2 >= d = d - m
295297 | otherwise = -m
296298
299+-- | Change the precision of a fixed-point number. If the new precision is
300+-- | less than the old precision, extra decimal places will be lost.
301+rescale
302+ :: forall precision1 precision2
303+ . KnownPrecision precision1
304+ => KnownPrecision precision2
305+ => Fixed precision1
306+ -> Fixed precision2
307+rescale =
308+ unsafePartial (fromJust <<< fromString <<< toString)
309+
297310-- | Division of fixed-precision numbers. This function is deprecated; you
298311-- | should use `/` from the `EuclideanRing` instance instead.
299312approxDiv
test/Main.purs+51−1
@@ -2,7 +2,7 @@ module Test.Main where
22
33import Prelude
44
5−import Data.Fixed (class KnownPrecision, Fixed, PProxy, fromNumber, toNumber, fromString, reifyPrecision, reflectPrecision, toString, P100)
5+import Data.Fixed (class KnownPrecision, Fixed, PProxy, fromNumber, toNumber, fromString, reifyPrecision, reflectPrecision, toString, P100, rescale, fromBigInt, floor)
66import Data.BigInt as BigInt
77import Data.Maybe (Maybe(..), fromJust, isJust)
88import Effect (Effect)
@@ -27,6 +27,28 @@ fromNumberWith
2727 -> Maybe (Fixed precision)
2828fromNumberWith _ = fromNumber
2929
30+-- | For type hinting.
31+withPrecisionOf
32+ :: forall precision
33+ . PProxy precision
34+ -> Fixed precision
35+ -> Fixed precision
36+withPrecisionOf _ x = x
37+
38+floorToPrecision
39+ :: forall precision
40+ . KnownPrecision precision
41+ => Int
42+ -> Fixed precision
43+ -> Fixed precision
44+floorToPrecision p =
45+ (_ / scaleFactor)
46+ <<< floor
47+ <<< (_ * scaleFactor)
48+ where
49+ scaleFactor =
50+ fromBigInt (BigInt.pow (BigInt.fromInt 10) (BigInt.fromInt p))
51+
3052main :: Effect Unit
3153main = do
3254 log "Commutative monoid under addition:"
@@ -123,3 +145,31 @@ main = do
123145 Nothing ->
124146 false
125147 <?> ("failed to roundtrip via Number: " <> show { precision, x })
148+
149+ log ""
150+ log "rescale"
151+ log ""
152+
153+ log "rescaling up then down should be no-op"
154+ quickCheck' 1000 do
155+ let lo = 10
156+ hi <- chooseInt 10 20
157+ unsafePartial fromJust $ join $
158+ reifyPrecision lo \lo_ ->
159+ reifyPrecision hi \hi_ -> do
160+ x <- genFixedP lo_
161+ let y = withPrecisionOf hi_ $ rescale x
162+ let xx = rescale y
163+ pure $ x == xx <?> show { x, xx, y }
164+
165+ log "rescaling down then up should be the same as flooring"
166+ quickCheck' 1000 do
167+ let hi = 20
168+ lo <- chooseInt 10 20
169+ unsafePartial fromJust $ join $
170+ reifyPrecision lo \lo_ ->
171+ reifyPrecision hi \hi_ -> do
172+ x <- genFixedP hi_
173+ let y = withPrecisionOf lo_ $ rescale x
174+ let xx = floorToPrecision lo x
175+ pure $ xx == rescale y <?> show { x, xx, y }