i am trying to print
>>> math.log(2 ** 62,2).is_integer()
which returns
False
Similarly,
>>> math.log(2**62,2).is_integer()
False
>>> math.log(2**26,2).is_integer()
True
>>> math.log(2**28,2).is_integer()
True
>>> math.log(2**31,2).is_integer()
False
>>> math.log(2**32,2).is_integer()
True
>>> math.log(2**33,2).is_integer()
True
>>> math.log(2**31,2).is_integer()
False
>>> math.log(2**30,2).is_integer()
True
>>> math.log(2**63,2).is_integer()
True
>>> math.log(2**64,2).is_integer()
True
>>> math.log(2**62,2).is_integer()
False
The results are very vague, varying differently for various integers.
Any ideas why?
EDIT
Sylvain mentioned here that
>>> math.log(2**62,2)
returns
62.00000000000001
why is that so? Please if anyone could explain this?
FYI -> for many numbers in range(100) it does returns proper integers as shown below
>>> for i in range(100):
print 'math.log(2**'+str(i)+',2)' + ' --> ' + str(float(math.log(2**i,2))) + ' Is Integer? --> ' + str(math.log(2**i,2).is_integer())
math.log(2**0,2) --> 0.0 Is Integer? --> True
math.log(2**1,2) --> 1.0 Is Integer? --> True
math.log(2**2,2) --> 2.0 Is Integer? --> True
math.log(2**3,2) --> 3.0 Is Integer? --> True
math.log(2**4,2) --> 4.0 Is Integer? --> True
math.log(2**5,2) --> 5.0 Is Integer? --> True
math.log(2**6,2) --> 6.0 Is Integer? --> True
math.log(2**7,2) --> 7.0 Is Integer? --> True
math.log(2**8,2) --> 8.0 Is Integer? --> True
math.log(2**9,2) --> 9.0 Is Integer? --> True
math.log(2**10,2) --> 10.0 Is Integer? --> True
math.log(2**11,2) --> 11.0 Is Integer? --> True
math.log(2**12,2) --> 12.0 Is Integer? --> True
math.log(2**13,2) --> 13.0 Is Integer? --> True
math.log(2**14,2) --> 14.0 Is Integer? --> True
math.log(2**15,2) --> 15.0 Is Integer? --> True
math.log(2**16,2) --> 16.0 Is Integer? --> True
math.log(2**17,2) --> 17.0 Is Integer? --> True
math.log(2**18,2) --> 18.0 Is Integer? --> True
math.log(2**19,2) --> 19.0 Is Integer? --> True
math.log(2**20,2) --> 20.0 Is Integer? --> True
math.log(2**21,2) --> 21.0 Is Integer? --> True
math.log(2**22,2) --> 22.0 Is Integer? --> True
math.log(2**23,2) --> 23.0 Is Integer? --> True
math.log(2**24,2) --> 24.0 Is Integer? --> True
math.log(2**25,2) --> 25.0 Is Integer? --> True
math.log(2**26,2) --> 26.0 Is Integer? --> True
math.log(2**27,2) --> 27.0 Is Integer? --> True
math.log(2**28,2) --> 28.0 Is Integer? --> True
math.log(2**29,2) --> 29.0 Is Integer? --> False
math.log(2**30,2) --> 30.0 Is Integer? --> True
math.log(2**31,2) --> 31.0 Is Integer? --> False
math.log(2**32,2) --> 32.0 Is Integer? --> True
math.log(2**33,2) --> 33.0 Is Integer? --> True
math.log(2**34,2) --> 34.0 Is Integer? --> True
math.log(2**35,2) --> 35.0 Is Integer? --> True
math.log(2**36,2) --> 36.0 Is Integer? --> True
math.log(2**37,2) --> 37.0 Is Integer? --> True
math.log(2**38,2) --> 38.0 Is Integer? --> True
math.log(2**39,2) --> 39.0 Is Integer? --> False
math.log(2**40,2) --> 40.0 Is Integer? --> True
math.log(2**41,2) --> 41.0 Is Integer? --> True
math.log(2**42,2) --> 42.0 Is Integer? --> True
math.log(2**43,2) --> 43.0 Is Integer? --> True
math.log(2**44,2) --> 44.0 Is Integer? --> True
math.log(2**45,2) --> 45.0 Is Integer? --> True
math.log(2**46,2) --> 46.0 Is Integer? --> True
math.log(2**47,2) --> 47.0 Is Integer? --> False
math.log(2**48,2) --> 48.0 Is Integer? --> True
math.log(2**49,2) --> 49.0 Is Integer? --> True
math.log(2**50,2) --> 50.0 Is Integer? --> True
math.log(2**51,2) --> 51.0 Is Integer? --> False
math.log(2**52,2) --> 52.0 Is Integer? --> True
math.log(2**53,2) --> 53.0 Is Integer? --> True
math.log(2**54,2) --> 54.0 Is Integer? --> True
math.log(2**55,2) --> 55.0 Is Integer? --> False
math.log(2**56,2) --> 56.0 Is Integer? --> True
math.log(2**57,2) --> 57.0 Is Integer? --> True
math.log(2**58,2) --> 58.0 Is Integer? --> False
math.log(2**59,2) --> 59.0 Is Integer? --> False
math.log(2**60,2) --> 60.0 Is Integer? --> True
math.log(2**61,2) --> 61.0 Is Integer? --> True
math.log(2**62,2) --> 62.0 Is Integer? --> False
math.log(2**63,2) --> 63.0 Is Integer? --> True
math.log(2**64,2) --> 64.0 Is Integer? --> True
math.log(2**65,2) --> 65.0 Is Integer? --> True
math.log(2**66,2) --> 66.0 Is Integer? --> True
math.log(2**67,2) --> 67.0 Is Integer? --> True
math.log(2**68,2) --> 68.0 Is Integer? --> True
math.log(2**69,2) --> 69.0 Is Integer? --> True
math.log(2**70,2) --> 70.0 Is Integer? --> True
math.log(2**71,2) --> 71.0 Is Integer? --> True
math.log(2**72,2) --> 72.0 Is Integer? --> True
math.log(2**73,2) --> 73.0 Is Integer? --> True
math.log(2**74,2) --> 74.0 Is Integer? --> True
math.log(2**75,2) --> 75.0 Is Integer? --> True
math.log(2**76,2) --> 76.0 Is Integer? --> True
math.log(2**77,2) --> 77.0 Is Integer? --> True
math.log(2**78,2) --> 78.0 Is Integer? --> False
math.log(2**79,2) --> 79.0 Is Integer? --> True
math.log(2**80,2) --> 80.0 Is Integer? --> True
math.log(2**81,2) --> 81.0 Is Integer? --> True
math.log(2**82,2) --> 82.0 Is Integer? --> True
math.log(2**83,2) --> 83.0 Is Integer? --> True
math.log(2**84,2) --> 84.0 Is Integer? --> True
math.log(2**85,2) --> 85.0 Is Integer? --> True
math.log(2**86,2) --> 86.0 Is Integer? --> True
math.log(2**87,2) --> 87.0 Is Integer? --> True
math.log(2**88,2) --> 88.0 Is Integer? --> True
math.log(2**89,2) --> 89.0 Is Integer? --> True
math.log(2**90,2) --> 90.0 Is Integer? --> True
math.log(2**91,2) --> 91.0 Is Integer? --> True
math.log(2**92,2) --> 92.0 Is Integer? --> True
math.log(2**93,2) --> 93.0 Is Integer? --> False
math.log(2**94,2) --> 94.0 Is Integer? --> False
math.log(2**95,2) --> 95.0 Is Integer? --> False
math.log(2**96,2) --> 96.0 Is Integer? --> True
math.log(2**97,2) --> 97.0 Is Integer? --> True
math.log(2**98,2) --> 98.0 Is Integer? --> True
math.log(2**99,2) --> 99.0 Is Integer? --> True
All results are floats. is_integer
does not check if the type of the result is integer. It checks if the floating value is an integer.
Rounding errors might made is_integer
not reliable though:
>>> math.log(2**26,2)
26.0
>>> math.log(2**62,2)
62.00000000000001
As the above operation are performed through the use of the natural logarithm, I guess the rounding error here is introduced by the division by log(2)
(as math.log(x,2)
is math.log(x)/math.log(2)
).
For numbers above 2**53 the explanation is that double precision (64-bit) floating point numbers cannot represent integers bigger than that exactly. The logarithm function in these cases is already receiving an approximate input and of course it cannot provide exact output.
EDIT: powers of two can be represented exactly... the problem is for integers that are NOT a power of two and bigger than 2**53.
That log fails doing an exact computation for 2**31 is indeed somewhat surprising given that apparently most common hardware for PC today has instructions for computing logarithms in base 2 in the floating point unit.
Python code is however written in C and the C library doesn't provide a logarithm in base 2 library function in all build environments Python supports. This means that all computations are done passing from natural logarithm and a change of base; this explains inaccuracies even with small values like 2**31. For the generic math.log
function there's no special handling for the case base is 2 even if the compiler provides support for it.
Python 3 math
module contains however a log2
function and the code for computing the logarithm in base 2 uses a log2
primitive if this is present on the platform. Indeed in Linux math.log2(2**31)
is exact, while math.log(2**31, 2)
is not. I've read somewhere that Microsoft C++ math library doesn't implement log2
and thus I don't expect it to be exact in Python 3 implementation running in Windows (Python code is compiled with Visual C++).
EDIT: seems this is not true any more or was never true. math.log2
is accurate even on Windows builds of Python 3.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With