module Factory.Math.Precision(
ConvergenceOrder,
ConvergenceRate,
DecimalDigits,
linearConvergence,
quadraticConvergence,
cubicConvergence,
quarticConvergence,
getIterationsRequired,
getTermsRequired,
roundTo,
promote,
simplify
) where
import qualified Data.Ratio
type ConvergenceOrder = Int
type ConvergenceRate = Double
type DecimalDigits = Int
linearConvergence :: ConvergenceOrder
linearConvergence :: ConvergenceOrder
linearConvergence = ConvergenceOrder
1
quadraticConvergence :: ConvergenceOrder
quadraticConvergence :: ConvergenceOrder
quadraticConvergence = ConvergenceOrder
2
cubicConvergence :: ConvergenceOrder
cubicConvergence :: ConvergenceOrder
cubicConvergence = ConvergenceOrder
3
quarticConvergence :: ConvergenceOrder
quarticConvergence :: ConvergenceOrder
quarticConvergence = ConvergenceOrder
4
getIterationsRequired :: Integral i
=> ConvergenceOrder
-> DecimalDigits
-> DecimalDigits
-> i
getIterationsRequired :: ConvergenceOrder -> ConvergenceOrder -> ConvergenceOrder -> i
getIterationsRequired ConvergenceOrder
convergenceOrder ConvergenceOrder
initialDecimalDigits ConvergenceOrder
requiredDecimalDigits
| ConvergenceOrder
initialDecimalDigits ConvergenceOrder -> ConvergenceOrder -> Bool
forall a. Ord a => a -> a -> Bool
<= ConvergenceOrder
0 = [Char] -> i
forall a. HasCallStack => [Char] -> a
error ([Char] -> i) -> [Char] -> i
forall a b. (a -> b) -> a -> b
$ [Char]
"Factory.Math.Precision.getIterationsRequired:\tinsufficient 'initialDecimalDigits'; " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ConvergenceOrder -> [Char]
forall a. Show a => a -> [Char]
show ConvergenceOrder
initialDecimalDigits
| Double
precisionRatio Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
1 = i
0
| Bool
otherwise = Double -> i
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double -> i) -> Double -> i
forall a b. (a -> b) -> a -> b
$ ConvergenceOrder -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ConvergenceOrder
convergenceOrder Double -> Double -> Double
forall a. Floating a => a -> a -> a
`logBase` Double
precisionRatio
where
precisionRatio :: Double
precisionRatio :: Double
precisionRatio = ConvergenceOrder -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ConvergenceOrder
requiredDecimalDigits Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ ConvergenceOrder -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ConvergenceOrder
initialDecimalDigits
getTermsRequired :: Integral i
=> ConvergenceRate
-> DecimalDigits
-> i
getTermsRequired :: Double -> ConvergenceOrder -> i
getTermsRequired Double
_ ConvergenceOrder
0 = i
0
getTermsRequired Double
convergenceRate ConvergenceOrder
requiredDecimalDigits
| Double
convergenceRate Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
0 Bool -> Bool -> Bool
|| Double
convergenceRate Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
>= Double
1 = [Char] -> i
forall a. HasCallStack => [Char] -> a
error ([Char] -> i) -> [Char] -> i
forall a b. (a -> b) -> a -> b
$ [Char]
"Factory.Math.Precision.getTermsRequired:\t(0 < convergence-rate < 1); " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Double -> [Char]
forall a. Show a => a -> [Char]
show Double
convergenceRate
| ConvergenceOrder
requiredDecimalDigits ConvergenceOrder -> ConvergenceOrder -> Bool
forall a. Ord a => a -> a -> Bool
< ConvergenceOrder
0 = [Char] -> i
forall a. HasCallStack => [Char] -> a
error ([Char] -> i) -> [Char] -> i
forall a b. (a -> b) -> a -> b
$ [Char]
"Factory.Math.Precision.getTermsRequired:\t'requiredDecimalDigits' must be positive; " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ ConvergenceOrder -> [Char]
forall a. Show a => a -> [Char]
show ConvergenceOrder
requiredDecimalDigits
| Bool
otherwise = Double -> i
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double -> i) -> Double -> i
forall a b. (a -> b) -> a -> b
$ ConvergenceOrder -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ConvergenceOrder
requiredDecimalDigits Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double -> Double
forall a. Num a => a -> a
negate (Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
10 Double
convergenceRate)
roundTo :: (RealFrac a, Fractional f) => DecimalDigits -> a -> f
roundTo :: ConvergenceOrder -> a -> f
roundTo ConvergenceOrder
decimals = (f -> f -> f
forall a. Fractional a => a -> a -> a
/ Integer -> f
forall a. Num a => Integer -> a
fromInteger Integer
promotionFactor) (f -> f) -> (a -> f) -> a -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> f
forall a. Num a => Integer -> a
fromInteger (Integer -> f) -> (a -> Integer) -> a -> f
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
round (a -> Integer) -> (a -> a) -> a -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> a
forall a. Num a => a -> a -> a
* Integer -> a
forall a. Num a => Integer -> a
fromInteger Integer
promotionFactor) where
promotionFactor :: Integer
promotionFactor :: Integer
promotionFactor = Integer
10 Integer -> ConvergenceOrder -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ ConvergenceOrder
decimals
promote :: Num n => n -> DecimalDigits -> n
promote :: n -> ConvergenceOrder -> n
promote n
x = (n -> n -> n
forall a. Num a => a -> a -> a
* n
x) (n -> n) -> (ConvergenceOrder -> n) -> ConvergenceOrder -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n
10 n -> ConvergenceOrder -> n
forall a b. (Num a, Integral b) => a -> b -> a
^)
simplify :: RealFrac operand
=> DecimalDigits
-> operand
-> Rational
simplify :: ConvergenceOrder -> operand -> Rational
simplify ConvergenceOrder
decimalDigits operand
operand = operand -> operand -> Rational
forall a. RealFrac a => a -> a -> Rational
Data.Ratio.approxRational operand
operand (operand -> Rational)
-> (operand -> operand) -> operand -> Rational
forall b c a. (b -> c) -> (a -> b) -> a -> c
. operand -> operand
forall a. Fractional a => a -> a
recip (operand -> Rational) -> operand -> Rational
forall a b. (a -> b) -> a -> b
$ operand
4 operand -> operand -> operand
forall a. Num a => a -> a -> a
* operand
10 operand -> ConvergenceOrder -> operand
forall a b. (Num a, Integral b) => a -> b -> a
^ ConvergenceOrder -> ConvergenceOrder
forall a. Enum a => a -> a
succ ConvergenceOrder
decimalDigits