问题
I have the following Haskell script which computes the function f(x) = (2- x) - (2^3 - x^3/12)
calc x = (x - (x ^ 3) / 12)
calc2 x = (calc 2) - (calc x)
calcList1 :: [Float] -> Float
calcList1 l = foldl (+) 0.0 (map calc2 l)
calcList2 :: [Float] -> Float
calcList2 l = foldr (+) 0.0 (map calc2 l)
test1 :: Float -> Float
test1 step = (calcList1 l) - (calcList2 l)
where
l = [0.0,step..2.0]
Function calcList1 and calcList2 run calc2 function on each of list and then uses foldl and foldr respectively to sum the list. I was expecting both function to return the same answer but it does not.
*Main> test1 0.1
9.536743e-7
*Main> test1 0.01
2.2888184e-5
*Main> test1 0.001
2.4414063e-4
*Main> test1 0.0001
-3.7109375e-2
*Main>
Now I am confused. I can't see why numerical issues has to be involved here. Fold are essentially how ones collect each element which should be same in both cases, right?
回答1:
In general, the order in which floating point values are added is important. An entry point for own research could be http://en.wikipedia.org/wiki/Loss_of_significance . To summarize the basic caveat, in an oversimplified form:
Due to the limited number of significant bits, you have to assume something like
100000000000000000.0 + 1.0 = 100000000000000000.0
in floating-point computations. Consequently, when computing
100000000000000000.0
+ 1.0
- 100000000000000000.0
the result will be 0.0 - and thus, be different from
100000000000000000.0
- 100000000000000000.0
+ 1.0
where the result will be 1.0.
来源:https://stackoverflow.com/questions/21454929/numerical-issue-with-foldl-and-foldr-in-haskell