Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are Float and Double different in the case of adding 0.1 and 0.2?

Tags:

haskell

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?

like image 768
pikapika Avatar asked Nov 29 '22 13:11

pikapika


1 Answers

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.

like image 138
alias Avatar answered Dec 10 '22 12:12

alias