Log(2 ** 62,2).is_integer() 返回 false,为什么?

4 投票
2 回答
636 浏览
提问于 2025-04-18 18:22

我正在尝试打印

>>> math.log(2 ** 62,2).is_integer()

这段代码返回了

False

类似的,

>>> 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

结果非常模糊,对于不同的整数返回的结果也不一样。

有人知道这是为什么吗?

编辑

Sylvain在这里提到

>>> math.log(2**62,2) 

返回了

62.00000000000001

这是为什么呢?如果有人能解释一下就好了。

顺便说一下,对于范围在100以内的很多数字,它确实返回了正确的整数,如下所示

>>> 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

2 个回答

3

对于大于2的53次方的数字,原因在于双精度(64位)浮点数无法准确表示比这更大的整数。因此,在这些情况下,计算对数时输入的值已经是近似的,当然输出也无法精确。

补充说明:2的幂次方可以被准确表示……问题出在那些不是2的幂次方且大于2的53次方的整数上。

对于2的31次方,计算对数时出现不准确的情况确实让人感到意外,因为现在大多数个人电脑的硬件都有计算以2为底的对数的指令。

不过,Python的代码是用C语言写的,而C语言的库在所有Python支持的环境中并不都提供以2为底的对数函数。这意味着所有的计算都是通过自然对数和换底公式来完成的;这也解释了即使是像2的31次方这样的小值也会出现不准确的情况。对于通用的math.log函数,即使编译器支持以2为底的对数,也没有特别处理这种情况。

不过,Python 3的math模块中有一个log2函数,计算以2为底的对数时,如果平台上有log2这个原语,就会使用它。实际上,在Linux上,math.log2(2**31)是准确的,而math.log(2**31, 2)则不准确。我曾经看到过说微软的C++数学库没有实现log2,因此我不期待在Windows上运行的Python 3实现中它会是准确的(Python代码是用Visual C++编译的)。

补充说明:似乎这不再成立,或者从来就不是。math.log2在Windows版本的Python 3中也是准确的。

4

所有的结果都是浮点数is_integer这个方法并不是用来检查结果的类型是否是整数,而是用来检查这个浮点数的值是否是整数。

不过,由于四舍五入的误差,is_integer可能不太可靠:

>>> math.log(2**26,2)
26.0
>>> math.log(2**62,2)
62.00000000000001

因为上面的操作是通过自然对数来进行的,我猜测这里的四舍五入误差是由于除以log(2)引起的。
(因为math.log(x,2)实际上是math.log(x)/math.log(2)的结果)。

撰写回答