Python的multiply()和prod()返回错误结果
有人能解释一下这个问题吗?我在用Python 2.5。
考虑一下这个计算:1*3*5*7*9*11 ... *49。如果你在IPython的交互式控制台里输入这个,你会得到58435841445947272053455474390625L,这个结果是正确的。(为什么用奇数:这只是我最开始的做法)
使用Python的multiply.reduce()或者prod()函数,应该能得到相同的结果,针对相应的范围。确实可以,但到了一定程度就不对了。在这里,结果已经错了:
: k = range(1, 50, 2)
: multiply.reduce(k)
: -108792223
使用prod(k)也会得到-108792223作为结果。对于长度为12的相应范围(也就是k = range(1,24,2)),其他错误的结果也开始出现。
我不太明白为什么会这样。有人能帮忙解释一下吗?
2 个回答
CPU(中央处理器)并不能随便处理非常大的数字,它只能对特定范围内的数字进行操作,这些数字是用二进制表示的,也就是0和1的组合。
而在Python中,使用'*'这个符号来进行乘法时,可以很好地处理大整数。这是因为Python有自己的一套表示方法和特别的代码,超出了CPU或浮点运算单元(FPU)直接支持的乘法指令。
这在编程语言中其实是比较特别的。
在大多数其他编程语言中,数字通常是以固定的比特数组来表示的。比如在C语言或SQL中,你可以选择使用一个8位的整数,这样它可以表示从0到255,或者从-128到+127;你也可以选择使用一个16位的整数,它可以表示到2的16次方减1,也就是65535。当只能表示有限范围的数字时,如果你用乘法(*)或加法(+)等操作超出了这个范围,就可能会出现不好的结果,比如得到一个负数。你可能在使用某个外部库时遇到过这样的问题,这个库可能是用C语言写的,而不是Python。
这是因为 numpy.multiply.reduce()
会把范围列表转换成 numpy.int32
类型的数组,而在某个时刻,进行的计算超出了32位能存储的范围,导致溢出:
>>> type(numpy.multiply.reduce(range(1, 50, 2)))
<type 'numpy.int32'>
正如Mike Graham所说,你可以使用 dtype
参数来选择使用Python的整数,而不是默认的类型:
>>> res = numpy.multiply.reduce(range(1, 50, 2), dtype=object)
>>> res
58435841445947272053455474390625L
>>> type(res)
<type 'long'>
但是在这种情况下,用numpy来处理Python对象是没有意义的,最好的解决方案是KennyTM的建议:
>>> import functools, operator
>>> functools.reduce(operator.mul, range(1, 50, 2))
58435841445947272053455474390625L