我对random.random()函数在python中的工作方式有点困惑。
docs表示它'返回[0.0,1.0)范围内的下一个随机浮点数。 我知道伪随机数生成器通过对值执行某些操作来工作。通常,此值是生成器生成的先前数字。所以我认为'下一个随机浮点'在这里意味着什么。 (如果我错了,请纠正我)
但是当我看到随机库的source code时,class Random
中没有定义随机函数。相反,它在class SystemRandom
中定义如下(代码的第671行):
def random(self):
"""Get the next random number in the range [0.0, 1.0)."""
return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPF
如果我理解正确,这个函数使用os.urandom生成一个随机数。根据{{3}},返回来自OS特定随机源的随机字节。所以这不会给'下一个'浮点随机数。
两者如何相连?或者他们是两个不同的东西?
我在这里很困惑。任何形式的帮助将不胜感激。
谢谢!
答案 0 :(得分:2)
Python中的random
模块包含pseudorandom number generators(PRNGs)的两个接口(类)。您可以将其视为生成随机数的两种方式。
random.random()在第749行的“ random.py”模块中定义(对我来说)
_inst = Random()
...
random = _inst.random
类random.Random()
本身并没有定义random()
方法,而是继承了_random.Random()
(它确实定义了称为random()
的方法),它是名为{{ 1}}位于模块Random()
上。
_random
(它是一个内置模块)模块的C
源代码可以在here(实际上称为_random
)中找到。请参见下面的说明)
Naming convention for modules in C/C++
(从历史上看,如果模块称为垃圾邮件,则C文件包含 实现称为spammodule.c;如果模块名称非常 很长,就像spammify一样,模块名称可以只是spammify.c。)
_randommodule.c
(或_random.Random.random()
)方法在random.random()
文件中定义为_random_Random_random_impl()
。
_randommodule.c
static PyObject *
_random_Random_random_impl(RandomObject *self)
{
uint32_t a=genrand_int32(self)>>5, b=genrand_int32(self)>>6;
return PyFloat_FromDouble((a*67108864.0+b)*(1.0/9007199254740992.0));
}
是由Mersenne Twister PRNG实现定义的函数,该函数返回4字节数字。
(我知道您没有要求SystemRandom(),但是在我写这篇文章时,我还没有意识到)
我将这张图片作为我的答案的概述(但是,我鼓励您阅读所有内容)
genrand_int32()
在模块SystemRandom().random()
中定义。
random.py
该函数使用模块 ...
def random(self):
"""Get the next random number in the range [0.0, 1.0)."""
return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPF**strong text**
os.py
from os import urandom as _urandom
模块并未定义函数os.py
本身,而是从内置模块导入的。如果您使用POSIX OS,则urandom()
将导入os.py
内置模块,如果您使用的是Windows NT OS,则将导入posix
内置模块。这些模块包含urandom()的定义。
nt
OR
if 'posix' in _names:
name = 'posix'
linesep = '\n'
from posix import *
elif 'nt' in _names: name = 'nt' linesep = '\r\n' from nt import *
和posix
是内置模块,因此它们没有nt
属性。
__file__
在urandom()
中定义为os_urandom_impl(),它调用_PyOS_URandom()。
posixmodule.c
static PyObject * os_urandom_impl(PyObject *module, Py_ssize_t size) { ... bytes = PyBytes_FromStringAndSize(NULL, size); ... result = _PyOS_URandom(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes)); ... return bytes }
在_PyOS_URandom()
文件中定义,然后调用pyurandom()
bootstrap_hash.c
int _PyOS_URandom(void *buffer, Py_ssize_t size) { return pyurandom(buffer, size, 1, 1); }
在pyurandom()
文件中定义,然后调用dev_urandom()。
bootstrap_hash.c
static int pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise) { ... return dev_urandom(buffer, size, raise); ... }
在dev_urandom
文件中定义,然后使用bootstrap_hash.c
目录获取随机字节。
/dev/urandom
它可能看起来有点怪(我也以为是),但是
static int dev_urandom(char *buffer, Py_ssize_t size, int raise) { ... fd = _Py_open("/dev/urandom", O_RDONLY); ... do { n = _Py_read(fd, buffer, (size_t)size); ... } while (0 < size); ... }
文件也用于NT系统,这是文件开头的引号(注释)此文件还用于Windows NT / MS-Win。在这种情况下
模块实际上称自己为“ nt”,而不是“ posix”,还有一些函数 没有实现或实现方式不同。来源
假设对于Windows NT,定义了宏“ MS_WINDOWS” 独立于所使用的编译器。不同的编译器定义它们的 自己的功能测试宏,例如'_MSC_VER'。
对于Windows NT,直到pyurandom()函数,函数调用链与POSIX相同
posixmodule.c
在pyurandom()
文件中定义,然后调用win32_urandom()。
bootstrap_hash.c
static int pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise) { ... #ifdef MS_WINDOWS return win32_urandom((unsigned char *)buffer, size, raise); #else ... }
在win32_urandom()
文件中定义,然后调用bootstrap_hash.c
。
CryptGenRandom()
static int win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise) { ... if (!CryptGenRandom(hCryptProv, chunk, buffer)) { ... } ... return 0; }
在CryptGenRandom()
文件中声明,并在wincrypt.h
和Advapi32.lib
库中定义(这些文件由Microsoft提供)
答案 1 :(得分:1)
random.random()
实际定义为here:
random = _inst.random
但是,它只是对C实现的引用。
以下是来源:
关于底层Mersenne Twister核心生成器的一般说明:
- 期限是2 ** 19937-1。
- 它是现存最广泛测试的发电机之一。
- random()方法在C中实现,在单个Python步骤中执行,因此是线程安全的。
您可能希望查看Mersenne Twister上的文章。简单地说,发电机的状态与“之前的数字”不一样,它要复杂得多。所以你错了«...伪随机数生成器通过对值执行某些操作来工作。通常,此值是生成器生成的先前数字»。
至于SystemRandom.random()
,它与random.random()
无关。在Python中,从不同模块导入的具有相同名称的函数是不同的,因此您不能在此处依赖函数的名称。
答案 2 :(得分:1)
这是你错过的片段(CPython32):
import _random
class Random(_random.Random):
_random.Random
类
>>> import _random
>>> dir(_random.Random)
[(...) 'getrandbits', 'getstate', 'jumpahead', 'random', 'seed', 'setstate']
,并且来自同一个random.py实现文件
开头的docstring关于底层Mersenne Twister核心生成器的一般说明:
- 期限是2 ** 19937-1。
- 它是现存最广泛测试的发电机之一。
- random()方法在C中实现,在单个Python步骤中执行, 因此,线程安全。
_random是一个已编译的C库,它包含一些基本操作,这些操作在random.py文件中包含的Python实现中进一步扩展。
答案 3 :(得分:0)
你是对的,这是使用os.urandom函数
from os import urandom as _urandom
BPF = 53 # Number of bits in a float
RECIP_BPF = 2**-BPF
def random():
"""Get the next random number in the range [0.0, 1.0)."""
return (int.from_bytes(_urandom(7), 'big') >> 3) * RECIP_BPF
print(random())
print(RECIP_BPF)
print(int.from_bytes(_urandom(7), 'big')>> 3)
print(int.from_bytes(_urandom(7), 'little') >> 3)
玩它,你会得到它。