在 Cython
[0,1]
中生成随机数的最有效和可移植的方法是什么?一种方法是使用 C 库中的 INT_MAX
和 rand()
:
from libc.stdlib cimport rand
cdef extern from "limits.h":
int INT_MAX
cdef float randnum = rand() / float(INT_MAX)
这样使用
INT_MAX
可以吗?我注意到它与从 Python 的 max int 获得的常量有很大不同:
import sys
print INT_MAX
print sys.maxint
产量:
2147483647 (C max int)
9223372036854775807 (python max int)
哪个是
rand()
的正确“标准化”数字? 编辑 另外,如果使用从 libc 调用 rand()
的 C 方法,如何设置随机种子(例如,根据当前时间播种)?
C 标准规定
rand
返回 0 到 RAND_MAX(含)范围内的 int
,因此将其除以 RAND_MAX(来自 stdlib.h
)是对其进行标准化的正确方法。实际上,RAND_MAX 几乎总是等于 MAX_INT,但不要依赖于此。
因为
rand
自 C89 以来一直是 ISO C 的一部分,因此保证它在任何地方都可用,但不保证其随机数的质量。不过,如果可移植性是您主要关心的问题,那么它是您的最佳选择,除非您愿意使用 Python 的 random
模块。
sys.maxint
是完全不同的概念;它只是 Python 可以用“它自己的”int 类型表示的最大正数;较大的必须是多头。 Python 的 int 和 long 与 C 的没有特别相关。
cdef extern from "stdlib.h":
double drand48()
void srand48(long int seedval)
cdef extern from "time.h":
long int time(int)
# srand48(time(0))
srand48(100)
# TODO: this is a seed to reproduce bugs, put to line of code above for
# production
drand48() #This gives a float in range [0,1)
我在研究你的除法方法是否产生足够的随机性时遇到了这个想法
。我发现的来源提出了一个很好的观点,在我的例子中,我将随机数与两位数的小数进行比较,因此我实际上只需要 3 个小数点的精度。所以 INT_MAX 已经足够了。但是,看起来 drand48 节省了除法成本,因此可能值得使用。
random.random()
:
import numpy as np
from ext.random import random as rd
%timeit rd()
48.6 ns ± 0.396 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
np.unique([rd() for _ in range(10000000)]).size
Out[5]: 32768
from random import random as rd_python
%timeit rd_python()
33.2 ns ± 0.213 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
np.unique([rd_python() for _ in range(10000000)]).size
Out[8]: 10000000
对于 cython 版本:
from libc.stdlib cimport rand, RAND_MAX
cpdef float random():
return float(rand()) / RAND_MAX
版本的值相同:
from libc.stdlib cimport rand, RAND_MAX
cdef float scale = 1.0 / RAND_MAX
cpdef float crandom():
return rand() * scale