-1

I have try this simple math operation in python

>>> math.floor(8.2-0.21)
7.0
>>> math.floor(8.21-0.2)
8.0
>>> math.floor(8.2-0.2)
7.0

The third one should return 8 but it is return 7?!

UPDATE

i have try it in PHP, ruby and JAVA and i have got the same results.

Update 2 i don't know why the question get many votes down !!

shox
  • 1,150
  • 5
  • 18
  • 32

4 Answers4

8

The languages you cite use either IEEE-754 64-bit binary floating-point or use the floating-point of the underlying hardware, which is likely IEEE-754 binary floating-point.

In IEEE-754 64-bit binary floating-point, the nearest representable value to 8.2 is 8.199999999999999289457264239899814128875732421875, and the nearest representable value to .2 is 0.200000000000000011102230246251565404236316680908203125.

So, when you write 8.2 - 0.2, what actually happens is that 0.200000000000000011102230246251565404236316680908203125 is subtracted from 8.199999999999999289457264239899814128875732421875. The result is a value slightly under 8, and the floor of a value slightly under 8 is 7.

The lesson here is that floating-point arithmetic is generally approximate, so you must be careful when evaluating functions with discontinuities (like floor) or steep slopes. You must either design your code to accept results that may cross the discontinuities or you must design your calculations to avoid errors that cross the discontinuities.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
4

Your first two examples are to be expected:

  • 8.2 - 0.21 is 7.99. Floor of 7.99 is 7, and that's what is returned. Remember that floor(x) is the greatest integer less than or equal to x. 8 is greater than 7.99, so it can't possibly be returned. 7, on the other hand, meets this requirement.

  • 8.21 - 0.2 is 8.01. Floor of 8.01 is 8 -- no magic here.


>>> math.floor(8.2-0.2)
7.0

Now this is more interesting. It has to do with the fact that 8.2 and 0.2 cannot be exactly represented with floats, so the result of the computation is perhaps not what you might have thought:

>>> 8.2 - 0.2
7.999999999999999

Again, floor() is working as documented.

You can see this for yourself using decimal:

>> from decimal import Decimal
>>> Decimal(0.2)
Decimal('0.200000000000000011102230246251565404236316680908203125')
>>> Decimal(8.2)
Decimal('8.199999999999999289457264239899814128875732421875')

Relevant: What Every Computer Scientist Should Know About Floating-Point Arithmetic

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • @EricPostpischil Nevermind, you are correct -- I was thinking of 0.8. The error stems from `8.2` and `0.2` themselves. I'll update the answer. – arshajii Oct 21 '13 at 21:51
0

Why should it be 8? Floor functions return the nearest integer rounded down, so those two examples are correct.

8.2 - 0.21 = 7.99, which rounded down is 7.

8.21 - 0.2 = 8.01, which rounded down is 8.

zo7
  • 126
  • 1
  • 2
0
>>> a=0.2
>>> a
0.20000000000000001
>>> b = 8.2
>>> b
8.1999999999999993
>>> b-a
7.9999999999999991
>>> math.floor(b-a)
7.0

Due to floating point inaccuracies

Steve Barnes
  • 27,618
  • 6
  • 63
  • 73