2

This is my code:

num = math.log(536870912) / math.log(2)  # num = 29.0
ceil = math.ceil(num)
floor = math.floor(num)
print(ceil, floor)

The output is (30.0, 29.0)

My question is when I just print math.ceil(29.0) the result is 29.0, why the above code gives me the 30.0 as ceiling?

李林泽
  • 31
  • 3
  • Floats are approximations and `num` might be a tiny bit off from 29.0 – khelwood Jun 08 '20 at 22:06
  • 1
    Because [floating point math is inaccurate](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) (which is as necessary as "our" decimal system is inherently flawed as well – you can't even write down an accurate decimal version of `1/3`!). – Jongware Jun 08 '20 at 22:06
  • 2
    if you print your num, you will see it's slightly above 29.0 (29.000000000000004) – dominik Jun 08 '20 at 22:08
  • Note that there's also [`math.log2`](https://docs.python.org/3/library/math.html#math.log2), which tends to be more accurate than the division version you have. You may also want to look into [`int.bit_length`](https://docs.python.org/3/library/stdtypes.html#int.bit_length). – Mark Dickinson Jun 10 '20 at 18:31

3 Answers3

3

This is due to the inaccuracies of floating point math in python.

Print the number too:

import math
num = math.log(536870912) / math.log(2)  # num = 29.0 (not actually)
ceil = math.ceil(num)
floor = math.floor(num)
print(num, ceil, floor)
29.000000000000004 30 29

ceil() will return the the next highest integer.

I suggest using round()

leopardxpreload
  • 767
  • 5
  • 17
  • 2
    Very good, but a more relevant link would be to [Python's official documentation](https://docs.python.org/3/tutorial/floatingpoint.html), which discusses this as well. – Jongware Jun 08 '20 at 22:29
  • Agreed official is best - Although sometimes the oficial documentation can be daunting for new users - It is a good habit to get into – leopardxpreload Jun 08 '20 at 22:33
1

Because num does not equal to 29.0 exactly. If you print it, you will get something like 29.000000000000004:

import math
num = math.log(536870912) / math.log(2)  # num = 29.0
print(num)
ceil = math.ceil(num)
floor = math.floor(num)
print(ceil, floor)

Output:

29.000000000000004
30 29

You can check out this article for more details.

Red
  • 26,798
  • 7
  • 36
  • 58
1

I could say because

math.log(536870912) / math.log(2) = 29.000000000000004

And

29.000000000000004 != 29.0

As usr2564301 points out, floating point math is inaccurate.

Edison
  • 870
  • 1
  • 13
  • 28