posit 2022.0.1.0 → 2022.0.1.1
raw patch · 8 files changed
+284/−53 lines, 8 filesdep +Chartdep +Chart-cairodep ~positPVP ok
version bump matches the API change (PVP)
Dependencies added: Chart, Chart-cairo
Dependency ranges changed: posit
API changes (from Hackage documentation)
Files
- ChangeLog.md +6/−0
- README.md +48/−2
- posit.cabal +14/−1
- src/Posit.hs +31/−30
- stack.yaml +9/−6
- test/Test/Algorithms.hs +36/−13
- test/TestElementaryFunctions.hs +139/−0
- test/TestPosit.hs +1/−1
ChangeLog.md view
@@ -1,5 +1,11 @@ # Changelog for Posit Numbers +# posit-2022.0.1.1++ * Fixed loss of precision bug in some of the Floating instances (exp,sin,cos)+ * Added a Charting test; command to run: stack test posit:test-posit-functions+ * Added test results to the README.md file+ # posit-2022.0.1.0 * Added Random and Uniform Instances
README.md view
@@ -1,4 +1,4 @@-# posit 2022.0.1.0+# posit 2022.0.1.1 The [Posit Standard 2022](https://posithub.org/docs/posit_standard-2.pdf), and [Posit Standard 3.2](https://posithub.org/docs/posit_standard.pdf), @@ -35,7 +35,7 @@ 'Posit16', 'Posit32', 'Posit64', 'Posit128', and 'Posit256' as well as, 'P8', 'P16', 'P32', 'P64', 'P128', and 'P256' are implemented and include a couple of auxiliary classes, like AltShow, AltFloating, and -FusedOps.+FusedOps. So, 3.2 scales by dynamic range, 2022 scales by precision. ``` class AltShow a where@@ -99,4 +99,50 @@ representation, it can provide 2^es word size, 2's complement fixed length integers. The 'scientific' library provides 'read' and 'show' instances.+++Well, so...+Iron sharpens Iron, or so they say.+So, the implementations might not be perfect, but... they pretty good!++Number of Accurate Bits `exp`:+++Number of Accurate Bits `log`:+++Number of Accurate Bits `sqrt`:+++Number of Accurate Bits `sin`:+++Number of Accurate Bits `cos`:+++Number of Accurate Bits `asin`:+++Number of Accurate Bits `acos`:+++Number of Accurate Bits `atan`:+++Number of Accurate Bits `sinh`:+++Number of Accurate Bits `cosh`:+++Number of Accurate Bits `asinh`:+++Number of Accurate Bits `acosh`:+++Number of Accurate Bits `atanh`:+++
posit.cabal view
@@ -1,7 +1,7 @@ cabal-version: 1.12 name: posit-version: 2022.0.1.0+version: 2022.0.1.1 description: The Posit Number format attempting to conform to the Posit Standard Versions 3.2 and 2022. Where Real numbers are approximated by `Maybe Rational` and sampled in a similar way to the projective real line. homepage: https://github.com/waivio/posit#readme bug-reports: https://github.com/waivio/posit/issues@@ -90,6 +90,19 @@ build-depends: base >=4.7 && <5, posit+ default-language: Haskell2010++test-suite test-posit-functions+ type: exitcode-stdio-1.0+ main-is: TestElementaryFunctions.hs+ hs-source-dirs:+ test+ ghc-options: -O2 -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >= 4.7 && < 5,+ posit >= 2022.0.1,+ Chart,+ Chart-cairo default-language: Haskell2010 -- Weigh based benchmark for Vector
src/Posit.hs view
@@ -704,10 +704,22 @@ approx_pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446 -approx_exp :: PositC es => Posit es -> Posit es -- Comment by Abigale Emily: xcddfffff-approx_exp x = approx_2exp taylor_approx_exp (x / lnOf2)+-- euler's constant+approx_e :: PositC es => Posit es+approx_e = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135 +approx_exp :: forall es. PositC es => Posit es -> Posit es -- Comment by Abigale Emily: xcddfffff+approx_exp (R bx) = fromIntegral (uSeed @es)^^m * (taylor_approx_expm1 (R c * log_USeed) + 1)+ where+ (m,c) = properFraction $ bx / luS+ R luS = log_USeed @es+++log_USeed :: forall es. PositC es => Posit es+log_USeed = approx_log $ fromIntegral (uSeed @es)++ approx_log :: PositC es => Posit es -> Posit es approx_log = funLogDomainReduction funLogTaylor -- lnOf2 * approx_log2 x -- the commented out was slightly less accurate @@ -732,13 +744,19 @@ approx_sin :: forall es. PositC es => Posit es -> Posit es approx_sin NaR = NaR approx_sin 0 = 0-approx_sin x = normalizedSine $ x / (2*approx_pi)+approx_sin (R x) = normalizedSine (R x')+ where+ (_, x') = properFraction $ x / twoPi+ R twoPi :: Posit es = 2 * approx_pi -approx_cos :: PositC es => Posit es -> Posit es+approx_cos :: forall es. PositC es => Posit es -> Posit es approx_cos NaR = NaR approx_cos 0 = 1-approx_cos x = normalizedCosine $ x / (2*approx_pi)+approx_cos (R x) = normalizedCosine (R x')+ where+ (_, x') = properFraction $ x / twoPi+ R twoPi :: Posit es = 2 * approx_pi approx_asin :: PositC es => Posit es -> Posit es@@ -854,18 +872,7 @@ | otherwise = tuma_approx_cos $ 2*approx_pi * x -- --- Approximation of 2^x Domain Reduction-approx_2exp :: PositC es => (Posit es -> Posit es) -> Posit es -> Posit es-approx_2exp _ NaR = NaR-approx_2exp _ 0 = 1-approx_2exp f x- | x < 0 = recip.approx_2exp f.negate $ x -- always calculate the positive method- | otherwise = case properFraction x of- (int,rem) -> fromIntegral (2^int) * f (lnOf2 * rem) --- -- Using the CORDIC domain reduction and some approximation function of log funLogDomainReduction :: forall es. PositC es => (Posit es -> Posit es) -> Posit es -> Posit es funLogDomainReduction _ NaR = NaR@@ -894,7 +901,6 @@ | otherwise = go (k + 1) (acc + term k) term :: Natural -> Posit es term k = (-1)^(k+1) * (x - 1)^k / fromIntegral k- @@ -915,20 +921,15 @@ -- --- calculate exp, its most accurate near zero--- sum k=0 to k=inf of the terms, iterate until a fixed point is reached-taylor_approx_exp :: forall es. PositC es => Posit es -> Posit es-taylor_approx_exp NaR = NaR-taylor_approx_exp 0 = 1-taylor_approx_exp z = go 0 0++-- exp x - 1, has a decent Taylor Series+taylor_approx_expm1 :: forall es. PositC es => Posit es -> Posit es+taylor_approx_expm1 x = go 0 [x^n / fromIntegral (fac n) | n <- [1..]] where- go :: Natural -> Posit es -> Posit es- go !k !acc- | acc == (acc + term k) = acc -- if x == x + dx then terminate and return x- | otherwise = go (k+1) (acc + term k)- term :: Natural -> Posit es- term k = (z^k) / (fromIntegral.fac $ k)---+ go :: Posit es -> [Posit es] -> Posit es+ go !acc (h:t) | acc == acc + h = acc+ | otherwise = go (acc + h) t +-- need to use a Taylor Series, the `tanh` formulation doesn't work because it requires something that depends on `exp` -- =====================================================================
stack.yaml view
@@ -2,8 +2,8 @@ # that coorispond to a specific GHC or Stackage version # resolver: nightly-2023-05-20 # ghc-9.4.5-# resolver: lts-20.21 # ghc-9.2.7-resolver: lts-19.33 # ghc-9.0.2+resolver: lts-20.26 # ghc-9.2.8+# resolver: lts-19.33 # ghc-9.0.2 # resolver: lts-18.28 # ghc-8.10.7 # resolver: lts-18.6 # ghc-8.10.4 # resolver: lts-16.31 # ghc-8.8.4 # Fails To Build! ghc: panic! (the 'impossible' happened)@@ -12,6 +12,9 @@ - . allow-newer: true extra-deps:+ # For Test+ - Chart-cairo-1.9.3+ - cairo-0.13.10.0 # For LiquidHaskell: - hashable-1.3.5.0 # lts-20.16 and below # - hashable-1.4.2.0 # ghc-9.4.4@@ -24,8 +27,8 @@ - smtlib-backends-process-0.3 # ghc-9.2.7 - git: https://github.com/ucsd-progsys/liquidhaskell # commit: <something> # ghc-9.4.4 "Generically" errors out! Ambiguous occurrence ‘Generically’: It could refer to... ‘GHC.Generics.Generically’ or 'Language.Haskell.Liquid.Types.Generics.Generically'- # commit: 63337d432b47c1ba1ec9925db0994fc5cdce3eaf # ghc-9.2.7- commit: b8780ee8d73d123adb39675ef87a2883f8aa1ecd # ghc-9.0.2+ commit: 63337d432b47c1ba1ec9925db0994fc5cdce3eaf # ghc-9.2.7+ # commit: b8780ee8d73d123adb39675ef87a2883f8aa1ecd # ghc-9.0.2 # commit: f917323a1f9db1677e592d6ffc81467d53588d70 # ghc-8.10.7 subdirs: - .@@ -35,6 +38,6 @@ - liquid-containers - liquid-ghc-prim - git: https://github.com/ucsd-progsys/liquid-fixpoint- # commit: 0e1a4725793740f495c26957044c56488d6e1efc # ghc-9.2.7- commit: 5aed39ec3210b9093ed635693d01bf351e25392f # ghc-9.0.2+ commit: 0e1a4725793740f495c26957044c56488d6e1efc # ghc-9.2.7+ # commit: 5aed39ec3210b9093ed635693d01bf351e25392f # ghc-9.0.2 # commit: 544f8b0ba6d03b060701961250cce012412039c4 # ghc-8.10.7
test/Test/Algorithms.hs view
@@ -154,32 +154,29 @@ -- Taylor series expansion and fixed point algorithm, most accurate near zero-funSinTaylor :: Posit256 -> Posit256-funSinTaylor NaR = NaR-funSinTaylor z = go 0 0+taylor_approx_sin :: forall es. PositC es => Posit es -> Posit es+taylor_approx_sin NaR = NaR+taylor_approx_sin z = go 0 0 where- go :: Natural -> Posit256 -> Posit256+ go :: PositC es => Natural -> Posit es -> Posit es go !k !acc | acc == (acc + term k) = acc | otherwise = go (k+1) (acc + term k)- term :: Natural -> Posit256+ term :: PositC es => Natural -> Posit es term k = (-1)^k * z^(2*k+1) / (fromIntegral.fac $ 2*k+1) -- --- -- Taylor series expansion and fixed point algorithm, most accurate near zero-funCosTaylor :: Posit256 -> Posit256-funCosTaylor NaR = NaR-funCosTaylor z = go 0 0+taylor_approx_cos :: forall es. PositC es => Posit es -> Posit es+taylor_approx_cos NaR = NaR+taylor_approx_cos z = go 0 0 where- go :: Natural -> Posit256 -> Posit256+ go :: PositC es => Natural -> Posit es -> Posit es go !k !acc | acc == (acc + term k) = acc | otherwise = go (k+1) (acc + term k)- term :: Natural -> Posit256+ term :: PositC es => Natural -> Posit es term k = (-1)^k * z^(2*k) / (fromIntegral.fac $ 2*k) -- @@ -384,6 +381,32 @@ ++-- calculate exp, its most accurate near zero+-- sum k=0 to k=inf of the terms, iterate until a fixed point is reached+taylor_approx_exp :: forall es. PositC es => Posit es -> Posit es+taylor_approx_exp NaR = NaR+taylor_approx_exp 0 = 1+taylor_approx_exp !z = go 0 0+ where+ go :: PositC es => Natural -> Posit es -> Posit es+ go !k !acc+ | acc == (acc + term k) = acc -- if x == x + dx then terminate and return x+ | otherwise = go (k+1) (acc + term k)+ term :: PositC es => Natural -> Posit es+ term !k = (z^k) / (fromIntegral.fac $ k)+--++++-- Approximation of 2^x Domain Reduction+approx_2exp :: PositC es => (Posit es -> Posit es) -> Posit es -> Posit es+approx_2exp _ NaR = NaR+approx_2exp _ 0 = 1+approx_2exp f x+ | x < 0 = recip.approx_2exp f.negate $ x -- always calculate the positive method+ | otherwise = case properFraction x of+ (int,rem) -> fromIntegral (2^int) * f (lnOf2 * rem)
+ test/TestElementaryFunctions.hs view
@@ -0,0 +1,139 @@+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main (main) where++import Data.Int (Int16)++import Posit (Posit, P16, Posit16, AltShow(..), pattern NaR)+import Posit.Internal.PositC+++import Graphics.Rendering.Chart.Easy+import Graphics.Rendering.Chart.Backend.Cairo+++main :: IO ()+main = do expPlotP16Posit16+ logPlotP16Posit16+ sinPlotsP16Posit16+ cosPlotsP16Posit16+ asinPlotsP16Posit16+ acosPlotsP16Posit16+ atanPlotsP16Posit16+ sinhPlotsP16Posit16+ coshPlotsP16Posit16+ asinhPlotsP16Posit16+ acoshPlotsP16Posit16+ atanhPlotsP16Posit16+ sqrtPlotsP16Posit16+--++sinPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of sin with P16 and Posit16.png" $ do+ let sineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (sin p) sin) | p <- enumFrom (NaR :: P16)]+ sinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (sin p) sin) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Sine"+ plot (line "sin P16 error" [sineP16])+ plot (line "sin Posit16 error" [sinePosit16])++cosPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of cos with P16 and Posit16.png" $ do+ let cosineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (cos p) cos) | p <- enumFrom (NaR :: P16)]+ cosinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (cos p) cos) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Cosine"+ plot (line "cos P16 error" [cosineP16])+ plot (line "cos Posit16 error" [cosinePosit16])++expPlotP16Posit16 = toFile def "./test/Results/Bits Accuracy of exp with P16 and Posit16.png" $ do+ let expP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (exp p) exp) | p <- enumFrom (NaR :: P16)]+ expPosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (exp p) exp) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 exp"+ plot (line "exp P16 error" [expP16])+ plot (line "exp Posit16 error" [expPosit16])++logPlotP16Posit16 = toFile def "./test/Results/Bits Accuracy of log with P16 and Posit16.png" $ do+ let lnP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (log p) log) | p <- enumFrom (0 :: P16)]+ lnPosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (log p) log) | p <- enumFrom (0 :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Log"+ plot (line "log P16 error" [lnP16])+ plot (line "log Posit16 error" [lnPosit16])++asinPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of asin with P16 and Posit16.png" $ do+ let arcsineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (asin p) sin) | p <- enumFromTo (-1 :: P16) 1]+ arcsinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (asin p) sin) | p <- enumFromTo (-1 :: Posit16) 1]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 arcSine"+ plot (line "asin P16 error" [arcsineP16])+ plot (line "asin Posit16 error" [arcsinePosit16])++acosPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of acos with P16 and Posit16.png" $ do+ let arccosineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (acos p) acos) | p <- enumFromTo (-1 :: P16) 1]+ arccosinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (acos p) acos) | p <- enumFromTo (-1 :: Posit16) 1]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 arcCosine"+ plot (line "acos P16 error" [arccosineP16])+ plot (line "acos Posit16 error" [arccosinePosit16])++atanPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of atan with P16 and Posit16.png" $ do+ let arctangentP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (atan p) atan) | p <- enumFrom (NaR :: P16)]+ arctangentPosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (atan p) atan) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 arcTangent"+ plot (line "atan P16 error" [arctangentP16])+ plot (line "atan Posit16 error" [arctangentPosit16])++sinhPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of sinh with P16 and Posit16.png" $ do+ let hypsineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (sinh p) sinh) | p <- enumFrom (NaR :: P16)]+ hypsinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (sinh p) sinh) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Hyperbolic Sine"+ plot (line "sinh P16 error" [hypsineP16])+ plot (line "sinh Posit16 error" [hypsinePosit16])++coshPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of cosh with P16 and Posit16.png" $ do+ let hypcosineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (cosh p) cosh) | p <- enumFrom (NaR :: P16)]+ hypcosinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (cosh p) cosh) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Hyperbolic Cosine"+ plot (line "cosh P16 error" [hypcosineP16])+ plot (line "cosh Posit16 error" [hypcosinePosit16])++asinhPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of asinh with P16 and Posit16.png" $ do+ let archypsineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (asinh p) asinh) | p <- enumFrom (NaR :: P16)]+ archypsinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (asinh p) asinh) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Hyperbolic Sine"+ plot (line "asinh P16 error" [archypsineP16])+ plot (line "asinh Posit16 error" [archypsinePosit16])++acoshPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of cosh with P16 and Posit16.png" $ do+ let archypcosineP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (acosh p) acosh) | p <- enumFrom (NaR :: P16)]+ archypcosinePosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (acosh p) acosh) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Hyperbolic Cosine"+ plot (line "acosh P16 error" [archypcosineP16])+ plot (line "acosh Posit16 error" [archypcosinePosit16])++atanhPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of atanh with P16 and Posit16.png" $ do+ let archyptangentP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (atanh p) atanh) | p <- enumFrom (NaR :: P16)]+ archyptangentPosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (atanh p) atanh) | p <- enumFrom (NaR :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Inv Hyperbolic Tangent"+ plot (line "atanh P16 error" [archyptangentP16])+ plot (line "atanh Posit16 error" [archyptangentPosit16])++sqrtPlotsP16Posit16 = toFile def "./test/Results/Bits Accuracy of sqrt with P16 and Posit16.png" $ do+ let sqrtP16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (sqrt p) sqrt) | p <- enumFrom (0 :: P16)]+ sqrtPosit16 = filter (\(_,d) -> not $ nanOrInf d) [(read (displayIntegral p) :: Double, err p (sqrt p) sqrt) | p <- enumFrom (0 :: Posit16)]+ layout_title .= "Number of Accurate Bits of P16 and Posit16 Square Root"+ plot (line "sqrt P16 error" [sqrtP16])+ plot (line "sqrt Posit16 error" [sqrtPosit16])++++err :: PositC es => Posit es -> Posit es -> (Double -> Double) -> Double+err NaR _ _ = 0 / 0+err _ NaR _ = 0 / 0+err p fp f = + let pDouble :: Double = fromRational.toRational $ p+ fpDouble :: Double = fromRational.toRational $ fp+ nBitsError = (negate.log.abs $ f pDouble - fpDouble) / log 2+ in max nBitsError 0++nanOrInf :: Double -> Bool+nanOrInf d = isNaN d || isInfinite d++++
test/TestPosit.hs view
@@ -252,7 +252,7 @@ print $ "Are there any `recip.recip /= id` values: " ++ (show rrne8) print $ "Does the distributive property hold with posits all the time?: " ++ (show doesItDistribute) print $ "Exaustive Proof... for fused ops recovering the distributeive property... and it turns out to be true."- print $ "Can fused ops recover the distributive property for `fmms a b (negate a) c == fam b c a` ?: " ++ (show fusedDistribute)+ -- print $ "Can fused ops recover the distributive property for `fmms a b (negate a) c == fam b c a` ?: " ++ (show fusedDistribute)