{-# LANGUAGE BangPatterns, NoImplicitPrelude #-}

module UnitFractionsDecomposition2 where

import GHC.Base
import GHC.Num ((+),(-),(*),abs,Integer)
import GHC.List (null,last,head,length,filter,sum,cycle,zip)
import Data.List (minimumBy)
import GHC.Real (Integral,round,fromIntegral,(/),truncate,ceiling)
import GHC.Float (sqrt)
import Data.Maybe (isNothing,isJust,fromJust,catMaybes)
import Data.Ord (comparing)
import Data.Tuple (fst,snd)

-- | Rounding to thousandth.
threeDigitsK :: Double -> Double
threeDigitsK :: Double -> Double
threeDigitsK Double
k = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round (Double
kforall a. Num a => a -> a -> a
*Double
1000)) forall a. Fractional a => a -> a -> a
/ Double
1000.0
{-# INLINE threeDigitsK #-}

-- | Characterizes the impact of the absolute error sign on the approximation. 
type ErrorImpact = Int

-- | Absolute error with sign for the two unit fractions approximations and the first argument
--  (a in the related paper) being taken as the second parameter for the function. 
--  The second argument here  is expected to be 'fromIntegral' @a0@ where 'Data.List.elem' @a0@ @[2..] == @ 'True'.
absErr2Frac :: Double -> Double -> Double
absErr2Frac :: Double -> Double -> Double
absErr2Frac Double
k Double
y = Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
y forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round (Double
yforall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
y forall a. Num a => a -> a -> a
- Double
1.0))) forall a. Num a => a -> a -> a
- Double
k
{-# INLINE absErr2Frac #-}

absErrUDecomp3 :: [Double] -> Double -> Double
absErrUDecomp3 :: [Double] -> Double -> Double
absErrUDecomp3 [Double
x,Double
y,Double
u] Double
k = Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
x forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round Double
y) forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
u forall a. Num a => a -> a -> a
- Double
k
absErrUDecomp3 [Double
x,Double
y] Double
k =  Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
x forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round Double
y) forall a. Num a => a -> a -> a
- Double
k
absErrUDecomp3 [Double
x] Double
k = Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round Double
x) forall a. Num a => a -> a -> a
- Double
k
absErrUDecomp3 [Double]
_ Double
_ = -Double
1.0
{-# INLINE absErrUDecomp3 #-}

elemSolution2 :: (Integral a) => Int -> a -> Double -> Bool
elemSolution2 :: forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2 ErrorImpact
n a
y Double
k = ErrorImpact
n forall a. Eq a => a -> a -> Bool
== ErrorImpact
0 Bool -> Bool -> Bool
|| forall a. Ord a => a -> a -> Ordering
compare ErrorImpact
n ErrorImpact
0 forall a. Eq a => a -> a -> Bool
== forall a. Ord a => a -> a -> Ordering
compare (Double -> Double -> Double
absErr2Frac Double
k (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
y)) Double
0
{-# INLINE elemSolution2 #-}


{- | Searches for the minimum absolute error solution to two unit fractions decomposition 
 (approximation) for the fraction in the 'isRangeN' 'True' values with taking into account
the sign of the absolute error. 

If the 'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
setOfSolutionsGmin :: ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin :: ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin ErrorImpact
n Double
k 
 | Double -> Bool
isRangeN Double
k = 
    let j :: Integer
j = forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
k)
        p :: Integer
p = forall a b. (RealFrac a, Integral b) => a -> b
truncate (forall a. Ord a => a -> a -> a
min (Double
2.0 forall a. Fractional a => a -> a -> a
/ Double
k) ((forall a. Floating a => a -> a
sqrt (Double
kforall a. Num a => a -> a -> a
*Double
k forall a. Num a => a -> a -> a
+ Double
16) forall a. Num a => a -> a -> a
- Double
k forall a. Num a => a -> a -> a
+ Double
4)forall a. Fractional a => a -> a -> a
/(Double
4forall a. Num a => a -> a -> a
*Double
k)))
        j1 :: Double
j1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
j in
            if Integer
j forall a. Eq a => a -> a -> Bool
== Integer
p 
                then if forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2 ErrorImpact
n Integer
j Double
k
                         then (Double
j1,Double
j1forall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
j1 forall a. Num a => a -> a -> a
- Double
1.0)) 
                         else (Double
0, -Double
1.0) 
                else (\Double
t -> if forall a. Num a => a -> a
abs (Double
t forall a. Num a => a -> a -> a
+ Double
0.0001) forall a. Ord a => a -> a -> Bool
< Double
0.000001
                                then (Double
0, Double
0) 
                                else (Double
t, Double
tforall a. Fractional a => a -> a -> a
/(Double
kforall a. Num a => a -> a -> a
*Double
t forall a. Num a => a -> a -> a
- Double
1.0))) forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
                                        forall a b. (a -> b -> b) -> b -> [a] -> b
foldr (\Double
x Double
y -> if forall a. Integral a => ErrorImpact -> a -> Double -> Bool
elemSolution2 ErrorImpact
n (forall a b. (RealFrac a, Integral b) => a -> b
round Double
x) Double
k Bool -> Bool -> Bool
&& forall a. Num a => a -> a
abs (Double -> Double -> Double
absErr2Frac Double
k Double
x) forall a. Ord a => a -> a -> Bool
< forall a. Num a => a -> a
abs (Double -> Double -> Double
absErr2Frac Double
k Double
y) 
                                                           then Double
x 
                                                           else Double
y) (-Double
0.0001) forall a b. (a -> b) -> a -> b
$ [Double
j1..forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
p]
 | Bool
otherwise = (Double
0, -Double
1.0)
{-# INLINE setOfSolutionsGmin #-}


-- | Searches for the minimum absolute error solution to two unit fractions decomposition 
-- (approximation) for the fraction in @k@ the 'isRangeN' @k = @ 'True'.
suitable2 :: Double -> (Double,Double)
suitable2 :: Double -> (Double, Double)
suitable2 = ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin ErrorImpact
0
{-# INLINE suitable2 #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
suitable21G :: ErrorImpact -> Double -> Maybe ([Double],Double)
suitable21G :: ErrorImpact -> Double -> Maybe ([Double], Double)
suitable21G ErrorImpact
n Double
k = 
   if forall a. Num a => a -> a
abs Double
x forall a. Ord a => a -> a -> Bool
< Double
0.000001 
       then forall a. Maybe a
Nothing 
       else forall a. a -> Maybe a
Just ([Double
x, Double
y], Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
x forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round Double
y) forall a. Num a => a -> a -> a
- Double
k) 
      where !(Double
x,Double
y) = ErrorImpact -> Double -> (Double, Double)
setOfSolutionsGmin ErrorImpact
n Double
k
{-# INLINE suitable21G #-}

suitable21 :: Double -> Maybe ([Double],Double)
suitable21 :: Double -> Maybe ([Double], Double)
suitable21 = ErrorImpact -> Double -> Maybe ([Double], Double)
suitable21G ErrorImpact
0
{-# INLINE suitable21 #-}

isRangeN :: Double -> Bool
isRangeN :: Double -> Bool
isRangeN Double
k = Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
0.9
{-# INLINE isRangeN #-}

-- | The preferable range of the argument for 'suitable2' and 'suitable21' functions. For arguments
-- in this range the functions always have informative results.
isRangeNPref :: Double -> Bool
isRangeNPref :: Double -> Bool
isRangeNPref Double
k = Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
< (Double
2.0forall a. Fractional a => a -> a -> a
/Double
3.0)
{-# INLINE isRangeNPref #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
check1FracDecompG :: ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG :: ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG ErrorImpact
n Double
k 
 | Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
0.501 = 
     let c :: Double
c = (Double
1.0forall a. Fractional a => a -> a -> a
/Double
k)
         err :: Double
err = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a b. (RealFrac a, Integral b) => a -> b
round Double
c) forall a. Num a => a -> a -> a
- Double
k
           in if Double
err forall a. Num a => a -> a -> a
* forall a b. (Integral a, Num b) => a -> b
fromIntegral ErrorImpact
n forall a. Ord a => a -> a -> Bool
>= Double
0  
                  then let cs :: [Double]
cs = [Double
c] in forall a. a -> Maybe a
Just ([Double]
cs, [Double] -> Double -> Double
absErrUDecomp3 [Double]
cs Double
k) 
                  else forall a. Maybe a
Nothing
 | Bool
otherwise = forall a. Maybe a
Nothing
{-# INLINE check1FracDecompG #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
check3FracDecompPartialG :: ErrorImpact -> Bool -> Double -> Maybe ([Double],Double)
check3FracDecompPartialG :: ErrorImpact -> Bool -> Double -> Maybe ([Double], Double)
check3FracDecompPartialG ErrorImpact
n Bool
direction = ErrorImpact
-> Bool -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
n Bool
direction []
{-# INLINE check3FracDecompPartialG #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign, 
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
check3FracDecompPartialPG :: ErrorImpact -> Bool -> [Int] -> Double -> Maybe ([Double],Double)
check3FracDecompPartialPG :: ErrorImpact
-> Bool -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
n Bool
direction [ErrorImpact]
ns Double
k 
 | Double
k forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
1 = 
     let u :: Maybe Double
u = (\[Double]
us -> if forall a. [a] -> Bool
null [Double]
us 
                         then forall a. Maybe a
Nothing 
                         else forall a. a -> Maybe a
Just (if Bool
direction then forall a. [a] -> a
last [Double]
us else forall a. [a] -> a
head [Double]
us)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (\Double
t -> let w :: Double
w = Double
k forall a. Num a => a -> a -> a
- Double
1.0forall a. Fractional a => a -> a -> a
/Double
t in 
                            Double
w forall a. Ord a => a -> a -> Bool
>= Double
0.005 Bool -> Bool -> Bool
&& Double
w forall a. Ord a => a -> a -> Bool
<= (Double
2.0forall a. Fractional a => a -> a -> a
/Double
3.0)) forall a b. (a -> b) -> a -> b
$ [Double
2.0..Double
10.0] forall a. Monoid a => a -> a -> a
`mappend` forall a b. (a -> b) -> [a] -> [b]
map forall a b. (Integral a, Num b) => a -> b
fromIntegral [ErrorImpact]
ns in 
                               if forall a. Maybe a -> Bool
isNothing Maybe Double
u 
                                   then forall a. Maybe a
Nothing 
                                   else let u1 :: Double
u1 = forall a. HasCallStack => Maybe a -> a
fromJust Maybe Double
u in let s2 :: Maybe ([Double], Double)
s2 = Double -> Maybe ([Double], Double)
suitable21 (Double
k forall a. Num a => a -> a -> a
- Double
1.0 forall a. Fractional a => a -> a -> a
/ Double
u1) in 
                                           if forall a. Maybe a -> Bool
isNothing Maybe ([Double], Double)
s2 
                                               then forall a. Maybe a
Nothing 
                                               else let ([Double
a1,Double
b1],Double
_) = forall a. HasCallStack => Maybe a -> a
fromJust Maybe ([Double], Double)
s2 in let err :: Double
err = [Double] -> Double -> Double
absErrUDecomp3 [Double
a1, Double
b1, Double
u1] Double
k in
                                                       if Double
err forall a. Num a => a -> a -> a
* forall a b. (Integral a, Num b) => a -> b
fromIntegral ErrorImpact
n forall a. Ord a => a -> a -> Bool
>= Double
0  
                                                           then forall a. a -> Maybe a
Just ([Double
u1,Double
a1,Double
b1], [Double] -> Double -> Double
absErrUDecomp3 [Double
a1, Double
b1, Double
u1] Double
k) 
                                                           else forall a. Maybe a
Nothing
 | Bool
otherwise = forall a. Maybe a
Nothing
{-# INLINE check3FracDecompPartialPG #-}

{- | Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
lessErrSimpleDecompPG :: ErrorImpact -> [Int] -> Double -> (Int,Maybe ([Double],Double),Double)
lessErrSimpleDecompPG :: ErrorImpact
-> [ErrorImpact]
-> Double
-> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompPG ErrorImpact
n [ErrorImpact]
ns Double
k = 
  (\[([Double], Double)]
ts -> if forall a. [a] -> Bool
null [([Double], Double)]
ts 
              then (ErrorImpact
0,forall a. Maybe a
Nothing,-Double
1.0) 
              else let p :: ([Double], Double)
p = forall (t :: * -> *) a.
Foldable t =>
(a -> a -> Ordering) -> t a -> a
minimumBy (forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (forall a. Num a => a -> a
abs forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd)) [([Double], Double)]
ts in (forall a. [a] -> ErrorImpact
length (forall a b. (a, b) -> a
fst ([Double], Double)
p), forall a. a -> Maybe a
Just ([Double], Double)
p, forall a b. (a, b) -> b
snd ([Double], Double)
p))  forall b c a. (b -> c) -> (a -> b) -> a -> c
. 
                              forall a. [Maybe a] -> [a]
catMaybes forall a b. (a -> b) -> a -> b
$ [ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG ErrorImpact
n Double
k,ErrorImpact -> Double -> Maybe ([Double], Double)
suitable21G ErrorImpact
n Double
k, ErrorImpact
-> Bool -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
n Bool
True [ErrorImpact]
ns Double
k, ErrorImpact
-> Bool -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
n Bool
False [ErrorImpact]
ns Double
k]

{-| Allows to take  into account the sign of the absolute error of the aproximation. If the 
'ErrorImpact' parameter is equal to 0 , then absolute error can be of any sign,
otherwise the sign of it is the same as the sign of the 'ErrorImpact' argument.
-}
lessErrDenomsPG :: ErrorImpact -> [Int] -> Double -> [Integer]
lessErrDenomsPG :: ErrorImpact -> [ErrorImpact] -> Double -> [Integer]
lessErrDenomsPG ErrorImpact
n [ErrorImpact]
ns = 
  (\(ErrorImpact
_,Maybe ([Double], Double)
ks,Double
_) -> if forall a. Maybe a -> Bool
isNothing Maybe ([Double], Double)
ks 
                    then [] 
                    else forall a b. (a -> b) -> [a] -> [b]
map forall a b. (RealFrac a, Integral b) => a -> b
round forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. HasCallStack => Maybe a -> a
fromJust forall a b. (a -> b) -> a -> b
$ Maybe ([Double], Double)
ks) forall b c a. (b -> c) -> (a -> b) -> a -> c
. ErrorImpact
-> [ErrorImpact]
-> Double
-> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompPG ErrorImpact
n [ErrorImpact]
ns
{-# INLINE lessErrDenomsPG #-}

--------------------------------------------

-- | Tries to approximate the fraction by just one unit fraction. Can be used for the numbers
-- between 0.005 and 0.501.
check1FracDecomp :: Double -> Maybe ([Double], Double)
check1FracDecomp :: Double -> Maybe ([Double], Double)
check1FracDecomp = ErrorImpact -> Double -> Maybe ([Double], Double)
check1FracDecompG ErrorImpact
0
{-# INLINE check1FracDecomp #-}

{- | Function to find the less by absolute value error approximation. One of the denominators is
taken from the range [2..10]. The two others are taken from the appropriate 'suitable21' 
applicattion.
-}
check3FracDecompPartial :: Bool -> Double -> Maybe ([Double],Double)
check3FracDecompPartial :: Bool -> Double -> Maybe ([Double], Double)
check3FracDecompPartial = ErrorImpact -> Bool -> Double -> Maybe ([Double], Double)
check3FracDecompPartialG ErrorImpact
0
{-# INLINE check3FracDecompPartial #-}

{- | Extended version of the 'check3FracDecompPartial' with the first denominator being taken not
 - only from the [2..10], but also from the custom user provided list. 
 - -}
check3FracDecompPartialP :: Bool -> [Int] -> Double -> Maybe ([Double],Double)
check3FracDecompPartialP :: Bool -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialP = ErrorImpact
-> Bool -> [ErrorImpact] -> Double -> Maybe ([Double], Double)
check3FracDecompPartialPG ErrorImpact
0
{-# INLINE check3FracDecompPartialP #-}


lessErrSimpleDecompP :: [Int] -> Double -> (Int,Maybe ([Double],Double),Double)
lessErrSimpleDecompP :: [ErrorImpact]
-> Double -> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompP = ErrorImpact
-> [ErrorImpact]
-> Double
-> (ErrorImpact, Maybe ([Double], Double), Double)
lessErrSimpleDecompPG ErrorImpact
0

-- | Returns a list of denominators for fraction decomposition using also those ones from the the list provided as the first argument. Searches for the least error from the checked ones.
lessErrDenomsP :: [Int] -> Double -> [Integer]
lessErrDenomsP :: [ErrorImpact] -> Double -> [Integer]
lessErrDenomsP = ErrorImpact -> [ErrorImpact] -> Double -> [Integer]
lessErrDenomsPG ErrorImpact
0
{-# INLINE lessErrDenomsP #-}

-- | Returns a unit fraction decomposition into 4 unit fractions. For the cases where the fraction
-- can be represented as a sum of three or less unit fractions, the last element in the resulting
-- list is really related to the floating-point arithmetic rounding errors and it depends on the
-- machine architecture and the realization of the floating-point arithmetic operations.
-- Almost any 'Double' value inside the [0.005, 2/3] can be rather well approximated by the sum of 4
-- unit fractions from the function here. There are also some intervals in the (2/3, 1] that have
-- also good approximations, though not every fraction is approximated well here.
lessErrSimpleDecomp4PG :: ErrorImpact -> [Int] -> Double -> ([Integer], Double)
lessErrSimpleDecomp4PG :: ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp4PG ErrorImpact
n [ErrorImpact]
ns Double
k = 
  let !ints :: [Integer]
ints = ErrorImpact -> [ErrorImpact] -> Double -> [Integer]
lessErrDenomsPG (- ErrorImpact
1) [ErrorImpact]
ns Double
k 
      !revs :: [Double]
revs = forall a b. (a -> b) -> [a] -> [b]
map (\Integer
t -> Double
1.0forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
t) [Integer]
ints
      !s :: Double
s = forall a. Num a => [a] -> a
sum [Double]
revs
      !err :: Double
err = Double
s forall a. Num a => a -> a -> a
- Double
k
      !reverr :: Double
reverr = Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a. Num a => a -> a
abs Double
err
      !next :: Integer
next 
        | ErrorImpact
n forall a. Ord a => a -> a -> Bool
> ErrorImpact
0 = forall a b. (RealFrac a, Integral b) => a -> b
truncate Double
reverr
        | ErrorImpact
n forall a. Ord a => a -> a -> Bool
< ErrorImpact
0 = forall a b. (RealFrac a, Integral b) => a -> b
ceiling Double
reverr
        | Bool
otherwise = forall a b. (RealFrac a, Integral b) => a -> b
round Double
reverr
      !err4 :: Double
err4 = Double
err forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
next in ([Integer]
ints forall a. Monoid a => a -> a -> a
`mappend` [Integer
next], Double
err4)

-- | Returns a unit fraction decomposition into 5 unit fractions. For the cases where the fraction
-- can be represented as a sum of three or less unit fractions, the last element(s) in the resulting
-- list is (are) really related to the floating-point arithmetic rounding errors and it depends on the
-- machine architecture and the realization of the floating-point arithmetic operations.
-- Almost any 'Double' value inside the [0.005, 2/3] can be rather well approximated by the sum of 5
-- unit fractions from the function here. There are also some intervals in the (2/3, 1] that have
-- also good approximations, though not every fraction is approximated well here.
lessErrSimpleDecomp5PG :: ErrorImpact -> [Int] -> Double -> ([Integer], Double)
lessErrSimpleDecomp5PG :: ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp5PG ErrorImpact
n [ErrorImpact]
ns Double
k = 
  let (![Integer]
ints, !Double
err4) = ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp4PG (- ErrorImpact
1) [ErrorImpact]
ns Double
k 
      !reverr :: Double
reverr = Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a. Num a => a -> a
abs Double
err4
      !next :: Integer
next 
        | ErrorImpact
n forall a. Ord a => a -> a -> Bool
> ErrorImpact
0 = forall a b. (RealFrac a, Integral b) => a -> b
truncate Double
reverr
        | ErrorImpact
n forall a. Ord a => a -> a -> Bool
< ErrorImpact
0 = forall a b. (RealFrac a, Integral b) => a -> b
ceiling Double
reverr
        | Bool
otherwise = forall a b. (RealFrac a, Integral b) => a -> b
round Double
reverr
      !err5 :: Double
err5 = Double
err4 forall a. Num a => a -> a -> a
+ Double
1.0 forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
next in ([Integer]
ints forall a. Monoid a => a -> a -> a
`mappend` [Integer
next], Double
err5)

----------------------------------------

-- | The argument should be greater or equal than 0.005 (1/200) though it is not checked. Returns the
-- representation of the fraction using canonical ancient Egyptian representation and its error as
-- 'Double' value in the resulting tuple.
egyptianFractionDecomposition :: Double -> ([(Integer,Integer)], Double)
egyptianFractionDecomposition :: Double -> ([(Integer, Integer)], Double)
egyptianFractionDecomposition Double
k 
  | Double
k forall a. Ord a => a -> a -> Bool
> Double
2.0forall a. Fractional a => a -> a -> a
/Double
3.0 Bool -> Bool -> Bool
&& Double
k forall a. Ord a => a -> a -> Bool
<= Double
1.0 = let ([Integer]
ks, Double
err) = ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp5PG ErrorImpact
0 [] (Double
k forall a. Num a => a -> a -> a
- Double
2.0forall a. Fractional a => a -> a -> a
/Double
3.0) in ((Integer
2,Integer
3) forall a. a -> [a] -> [a]
: forall a b. [a] -> [b] -> [(a, b)]
zip (forall a. [a] -> [a]
cycle [Integer
1]) [Integer]
ks, Double
err)
  | Bool
otherwise = let ([Integer]
ks, Double
err) = ErrorImpact -> [ErrorImpact] -> Double -> ([Integer], Double)
lessErrSimpleDecomp5PG ErrorImpact
0 [] Double
k in (forall a b. [a] -> [b] -> [(a, b)]
zip (forall a. [a] -> [a]
cycle [Integer
1]) [Integer]
ks, Double
err)