我遵循Hans Petter Langtangen的教程,以便更好地理解快速生成随机数的Cython。
作者有以下一行:
r = 1 + int(rand()/(RAND_MAX*6.0))
,它声称生成1到6之间的随机整数。对我来说,这看起来像一个错误,因为rand()
(从libc.stdlib
导入)正在生成一个从0到RAND_MAX
的随机整数,所以我猜
r = 1 + int(6*rand()/(RAND_MAX(1.0))
在这里应该更合适。因此,我创建了一个小的Cython脚本,该脚本应该在1和n
之间滚动一个随机整数,并在执行此操作时打印调试消息。脚本如下:
from libc.stdlib cimport rand, RAND_MAX
def print_rand(int n):
cdef int r
print "max", RAND_MAX
cdef int roll
roll = rand()
print "roll", roll
r = 1 + int(n*roll/(RAND_MAX*1.0))
print r
然后我使用以下setup.py
脚本编译脚本:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(name='Random print',
ext_modules=[Extension('_rand', ['rand.pyx'],)],
cmdclass={'build_ext': build_ext},)
通过
运行python setup.py build_ext --inplace
为了测试,我打开了IPython
,出现了以下神秘现象:
In [1]: import _rand
In [2]: _rand.print_rand(1000)
max 2147483647
roll 1804289383
1
但这没有意义,因为
In [3]: 1 + int(1000*1804289383/(2147483647*1.0))
Out[3]: 841
我在这里错过了什么?
乘法
n*roll
的结果太大,无法装入Cython int。与Python的int类型不同,当这种情况发生时,它会自动切换到任意精度表示,Cython处理溢出的方式与c类似。这通常意味着不合适的高位被丢弃;我不确定这是否是Cython中的未定义行为(在这种情况下可能会发生更糟糕的事情),或者Cython是否保证特定的溢出处理。