Reputation: 376
Can someone explain why
(0.1::Float) + (0.2::Float) == (0.3::Float)
while
(0.1::Double) + (0.2::Double) /= (0.3::Double)
To my knowledge Double is supposed to be more precise. Is there something about Float I should know about?
Upvotes: 5
Views: 764
Reputation: 30460
The first thing to realize is that when you enter 0.1::Double
and ghci prints 0.1
back, it's only an "illusion:"
Prelude Data.Ratio> 0.1::Double
0.1
Why is that an illusion? Because the number 0.1
is actually not precisely representable as a floating point number! This is true for both Float
and Double
. Observe:
Prelude Data.Ratio> toRational (0.1::Float)
13421773 % 134217728
Prelude Data.Ratio> toRational (0.1::Double)
3602879701896397 % 36028797018963968
So, in reality, these numbers are indeed "close" to the actual real number 0.1
, but neither is precisely 0.1
. How close are they? Let's find out:
Prelude Data.Ratio> toRational (0.1::Float) - (1%10)
1 % 671088640
Prelude Data.Ratio> toRational (0.1::Double) - (1%10)
1 % 180143985094819840
As you see, Double
is indeed a lot more precise than Float
; the difference between the representation of 0.1
as a Double
and the actual real-number 0.1
is a lot smaller. But neither is precise.
So, indeed the Double
addition is a lot more precise, and should be preferred over the Float
version. The confusing equality you see is nothing but the weird effect of rounding. The results of ==
should not be trusted in the floating-point land. In fact, there are many floating point numbers x
such that x == x + 1
holds. Here's one example:
Prelude> let x = -2.1474836e9::Float
Prelude> x == x + 1
True
A good read on floating-point representation is the classic What Every Computer Scientist Should Know about Floating-Point Arithmetic, which explains many of these quirky aspects of floating-point arithmetic.
Also note that this behavior is not unique to Haskell. Any language that uses IEEE754 Floating-point arithmetic will behave this way, which is the standard implemented by modern microprocessors.
Upvotes: 16
Reputation: 48611
Double
is indeed more precise. And yes, there is something you should know about floating point representations in general: you have to be very careful about how you use them! ==
is generally unlikely to actually be useful. You're generally going to want to compare floating point representations using more specialized functions, or at least check if the representation lies within some range rather than whether it has a certain value according to the built-in approximation.
Upvotes: 8