packages feed

exact-pi 0.4.0.0 → 0.4.1.0

raw patch · 3 files changed

+31/−3 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.ExactPi: rationalApproximations :: ExactPi -> [Rational]

Files

changelog.md view
@@ -1,3 +1,7 @@+0.4.1.0
+-------
+* Added function for computing rational approximations of ExactPi values.
+
 0.4.0.0
 -------
 * Added simpler constraints for converting ExactPi types to terms with the minimal context.
exact-pi.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                exact-pi
-version:             0.4.0.0
+version:             0.4.1.0
 synopsis:            Exact rational multiples of pi (and integer powers of pi)
 description:         Provides an exact representation for rational multiples of pi alongside an approximate representation of all reals.
                      Useful for storing and computing with conversion factors between physical units.
src/Data/ExactPi.hs view
@@ -27,12 +27,13 @@   isExactInteger,
   toExactInteger,
   isExactRational,
-  toExactRational
+  toExactRational,
+  rationalApproximations
 )
 where
 
 import Data.Monoid
-import Data.Ratio (numerator, denominator)
+import Data.Ratio ((%), numerator, denominator)
 import Prelude
 
 -- | Represents an exact or approximate real value.
@@ -92,6 +93,29 @@ toExactRational :: ExactPi -> Maybe Rational
 toExactRational (Exact 0 q) = Just q
 toExactRational _           = Nothing
+
+-- | Converts an 'ExactPi' to a list of increasingly accurate rational approximations, on alternating
+-- sides of the actual value. Note that 'Approximate' values are converted using the 'Real' instance
+-- for 'Double' into a singleton list. Note that exact rationals are also converted into a singleton list.
+--
+-- Implementation based on work by Anders Kaseorg shared at http://qr.ae/RbXl8M.
+rationalApproximations :: ExactPi -> [Rational]
+rationalApproximations (Approximate x) = [toRational (x :: Double)]
+rationalApproximations (Exact 0 q) = [q]
+rationalApproximations (Exact z q) = fmap (\pi' -> q * (pi' ^^ z)) piConvergents
+  where
+    piConvergents :: [Rational]
+    piConvergents = go True 2 4 where
+      go s p' q' | ltPi m = [q' | not s] ++ go True m q'
+                 | otherwise = [p' | s] ++ go False p' m where
+        m = (numerator p' + numerator q')%(denominator p' + denominator q')
+    ltPi :: Rational -> Bool
+    ltPi x = ok x 1 where
+      ok y i =
+        y <= (27*i - 12)%5 ||
+        (y < (675*i - 216)%125 &&
+         ok ((y - fromInteger (5*i - 2))*(3*(3*i + 1)*(3*i + 2)%(i*(2*i - 1))))
+            (i + 1))
 
 instance Show ExactPi where
   show (Exact z q) | z == 0 = "Exactly " ++ show q