Hunter McMillen
Hunter McMillen

Reputation: 61520

Precision when dividing by large integers

I am trying to write a function that computes ex (for the first 10 terms) given an integer `x.

The series expansion for ex is given by

1 + x + x2/2! + x3/3! + x4/4! + ....

The function itself was fairly easy to write, but I can't seem to understand Haskell type rules for division, i.e I want to divide an integer by a larger integer and get a floating-point result:

Here is what I have so currently

_eToX :: (Fractional a, Integral a) => a -> a -> a
_eToX x 0 = 1.0
_eToX x 1 = x
_eToX x n = ( fromIntegral(x^n) / fromIntegral(factorial n) ) + _eToX x (n - 1)

What I am doing above here makes sense to me, compute two integer results (x^n and factorial n) then evaluate them in a Floating point context using fromIntegral and /. This function however returns this error:

    1. Could not deduce (a ~ Integer)
    from the context (Fractional a, Integral a)
      bound by the type signature for
                 _eToX :: (Fractional a, Integral a) => a -> a -> a
      at /run-r4AWbVU9Fyph0OVhK3Dm/solution.hs:9:10-50
      `a' is a rigid type variable bound by
          the type signature for
            _eToX :: (Fractional a, Integral a) => a -> a -> a
          at /run-r4AWbVU9Fyph0OVhK3Dm/solution.hs:9:10
    In the return type of a call of `factorial'
    In the second argument of `(/)', namely `factorial n'
    In the first argument of `(+)', namely `(x ^ n / factorial n)'

    2. No instance for (Integral Double) arising from a use of `f'
    Possible fix: add an instance declaration for (Integral Double)
    In the expression: f
    In the second argument of `($)', namely
      `f $ map (read :: String -> Double) $ lines inputdata'
    In the second argument of `($)', namely
      `map show $ f $ map (read :: String -> Double) $ lines inputdata'

I am running the function with this main function:

main = do
   n <- readLn :: IO Int -- n doesnt really matter here because of getContents
   inputdata <- getContents
   mapM_ putStrLn $ map show $ f $ map (read :: String -> Double) $ lines inputdata

Upvotes: 1

Views: 263

Answers (3)

MoFu
MoFu

Reputation: 501

Is your f the given _eToX? your _eToX takes two arguments but you apply f to only one. This is fine as long as you only want a a partial application.

Concerning the error messages you should check the following:

What is the type of your factorial it seems to be something that has an Integer as an result and not something that implements the Typclasses Integral and fractional

You added a type annotation for your read function, s.t. it returns a Double Which is not an instance of Integral. But your f seems to take something as an argument which is an instance of Integral.

Upvotes: 0

John L
John L

Reputation: 28097

This type:

_eToX :: (Fractional a, Integral a) => a -> a -> a

doesn't make sense. You want the first argument and result to be Fractional, but the second argument, corresponding to the sequence position, should be Integral. Change the type to:

_eToX :: (Fractional a, Integral b) => a -> b -> a

Now there's a different error, arising from a missing Integral instance because of fromIntegral (x^n). ghci shows

Prelude> :t (^)
(^) :: (Integral b, Num a) => a -> b -> a

So it's not necessary to even use fromIntegral here, as the output is already the correct type. The final function is:

_eToX :: (Fractional a, Integral b) => a -> b -> a
_eToX x 0 = 1.0
_eToX x 1 = x
_eToX x n = ( (x^n) / fromIntegral(factorial n) ) + _eToX x (n - 1)

Upvotes: 4

DiegoNolan
DiegoNolan

Reputation: 3766

Here is what you are probably looking for.

eToX :: Integral a => Double -> a -> Double
eToX x 0 = 1
eToX x 1 = 1 + x
eToX x n = x^^n / (fromIntegral $ factorial n) + eToX x ( n - 1)

(^^) :: (Fractional a, Integral b) => a -> b -> a

You didn't want n and x to be the same. See how that power function does it.

Oh, and your equation was wrong for n = 1 you should have 1 + x

Upvotes: 0

Related Questions