Possible Duplicate:
Haskell ranges and floats
Why does the following output occur in haskel:
[0.1,0.3..1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
- What is the math behind the
1.0999999999999999(I am on a 64bit linux machine if its useful)? - Why doesnt it stop at
0.8999999999999999when obviously1.0999999999999999is out of range?
Why the overshoot?
[0.1,0.3..1]is short forenumFromThenTo 0.1 0.3 1.0The Haskell report says
Here
e3= 1.0 and your incrementi= 0.2, soe3 + i∕2= 1.1. It’s only supposed to stop when it goes bigger than that.You asked it to stop at 1, but it can only stop at 0.9 or 1.1. There’s a rounding error (floating types are inherently inaccurate) and 1.1 has ended up as 1.09999999999, so since this is not greater than 1.0 + i/2, it’s allowed.
In fact, even if it were equal to 1.0+i/2 it’s allowed, as you can check using the exact
[0.1,0.3..1]::[Rational](after importingData.Ratio).You can avoid the problem by calculating the upper limit you’re aiming for, 0.9, and specifying that:
[0.1,0.3..0.9]. You won’t suffer from rounding error unless your increment is small and your numbers are large, i.e. you’re working beyond the accuracy of Double for large numbers.Why the inaccuracy?
1.09 recurring is mathematically indistinguishable from 1.1, but here we have a finite number of 9s, and that’s strictly less than 1.1.
Floating point numbers are stored as if they’re in scientific notation, eg 4.563347×10^-7, but in binary, so like 01.1001110101×2^01101110.
This means your number can only be stored completely accurately as a Float if you can express it by summing powers of two, just as you can only write a number in decimal if you can express is by summing powers of 10.
0.2 in your example is 0.001100110011 in binary, with the 0011 repeating forever and 1.1 is 1.0001100110011 again with 0011 repeating forever.
Since only a finite part of those will be stored, when converted back to decimal to show you, they’ll be a little out. Often the difference is so small it gets rounded away again, but sometimes you can see it, as here.
This inherent inaccuracy is why
enumFromThenTolets you go above the top number – it’s stopping you from having too few because of rounding errors.