简体   繁体   中英

Implement the law of cosine in Haskell?

So I want to create my own cosine function using this formula: 在此处输入图片说明

The function should return the value as long as its absolute value is greater than 0.001.

However, my code seems to have some type errors that I just don't know how to fix. I've already tried changing all types to Double, but it still doesn't work.

fac :: Int -> Int
fac n = if (n == 0) then 1 else n * fac (n-1)

cos :: Double -> Double
cos x = sum [cos| k <- [0..],
                  let cos = (-1) * (x^(2*k) `div` fac (2*k)) , 
                  abs (cos) > 0.001]

This is the error:

• Couldn't match expected type 'Double' with actual type 'Int'

• In the second argument of 'div', namely 'fac (2 * k)'

There are basically two problems here:

  • div is for integer division (ie takes integral inputs, and produces an integral output by rounding down) only. You want (/) for floating-point division.
  • fac returns an Int , which you must explicitly convert to a floating-point number before using in division. (Many languages auto-convert from integral types to floating-point types, but Haskell does not.) You can use fromIntegral to convert.

Fixing these two things but nothing else, we get:

fac :: Int -> Int
fac n = if (n == 0) then 1 else n * fac (n-1)

cos :: Double -> Double
cos x = sum [cos| k <- [0..],
                  let cos = (-1) * (x^(2*k) / fromIntegral (fac (2*k))) , 
                  abs (cos) > 0.001]

This type-checks, though it has several other problems, in order from most important to least:

  • You were probably hoping that Haskell would somehow magically know that once abs cos <= 0.001 in one iteration, it will continue to be that for all future iterations, and stop iterating. But it doesn't. You said to draw k from [0..] , and so it will draw k from that entire list -- never finishing. You might like takeWhile instead.
  • You've lost the exponent k on -1 !
  • Even setting aside whether this is the most efficient formula to start from, your implementation repeats a lot of work. Each call to fac (2*k) must recompute all the previous factorials it had done as intermediate results; and your x^(2*k) repeats some work (though to a much lesser extent).
  • Reusing the name cos is pretty confusing. Although it doesn't technically make the program wrong , I'd avoid it.

I leave it to you to have fun exploring Haskell and learning how to fix these problems yourself -- I think it's well within the abilities you've shown here!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM