gpt4 book ai didi

multithreading - 在 Cython 中生成随机数的规范方法

转载 作者:行者123 更新时间:2023-12-02 08:50:39 24 4
gpt4 key购买 nike

生成伪均匀随机数([0, 1) 中的 double )的最佳方法是什么:

  1. 跨平台(最好具有相同的样本序列)
  2. 线程安全(显式传递 prng 或在内部使用线程本地状态)
  3. 无 GIL 锁
  4. 可以在 Cython 中轻松包装

有一个类似的post三年多前就已经讨论过这个问题,但很多答案并不符合所有标准。例如,drand48 是 POSIX 特定的。

我所知道的唯一似乎(但不确定)满足所有一些标准的方法是:

from libc.stdlib cimport rand, RAND_MAX

random = rand() / (RAND_MAX + 1.0)

注意@ogrisel asked大约 3 年前同样的问题。

编辑

调用rand不是线程安全的。感谢您指出@DavidW。

最佳答案

预回答警告:此答案建议使用 C++,因为该问题特别要求一个无需 GIL 即可运行的解决方案。如果您没有这个要求(而且您可能没有……),那么 Numpy 是最简单、最容易的解决方案。如果您一次生成大量数字,您会发现 Numpy 速度非常快。不要因为有人要求一个 no-gil 解决方案而被误导到包装 C++ 的复杂练习中。

<小时/>

原始答案:

我认为最简单的方法是使用 C++11 标准库,它提供 nice encapsulated random number generators and ways to use them 。这当然不是唯一的选择,您可以包装几乎任何合适的 C/C++ 库(一个好的选择可能是使用 numpy 使用的任何库,因为它很可能已经安装)。

我的一般建议是只包装您需要的部分,而不用担心完整的层次结构和所有可选的模板参数。通过示例,我展示了默认生成器之一,输入到均匀的浮点分布中。

# distutils: language = c++
# distutils: extra_compile_args = -std=c++11

cdef extern from "<random>" namespace "std":
cdef cppclass mt19937:
mt19937() # we need to define this constructor to stack allocate classes in Cython
mt19937(unsigned int seed) # not worrying about matching the exact int type for seed

cdef cppclass uniform_real_distribution[T]:
uniform_real_distribution()
uniform_real_distribution(T a, T b)
T operator()(mt19937 gen) # ignore the possibility of using other classes for "gen"

def test():
cdef:
mt19937 gen = mt19937(5)
uniform_real_distribution[double] dist = uniform_real_distribution[double](0.0,1.0)
return dist(gen)

(开头的 -std=c++11 用于 GCC。对于其他编译器,您可能需要调整它。无论如何,c++11 越来越多地成为默认值,因此您可以删除它)

引用您的标准:

  1. 跨平台,支持任何支持 C++ 的平台。我认为应该指定序列,以便它是可重复的。
  2. 线程安全,因为状态完全存储在 mt19937 对象中(每个线程应该有自己的 mt19937)。
  3. 没有 GIL - 它是 C++,没有 Python 部分
  4. 相当简单。
<小时/>

编辑:关于使用discrete_distribution

这有点困难,因为 discrete_distribution 的构造函数不太明显如何包装(它们涉及迭代器)。我认为最简单的事情是通过 C++ 向量,因为 Cython 内置了对此的支持,并且它很容易与 Python 列表相互转换

# use Cython's built in wrapping of std::vector
from libcpp.vector cimport vector

cdef extern from "<random>" namespace "std":
# mt19937 as before

cdef cppclass discrete_distribution[T]:
discrete_distribution()
# The following constructor is really a more generic template class
# but tell Cython it only accepts vector iterators
discrete_distribution(vector.iterator first, vector.iterator last)
T operator()(mt19937 gen)

# an example function
def test2():
cdef:
mt19937 gen = mt19937(5)
vector[double] values = [1,3,3,1] # autoconvert vector from Python list
discrete_distribution[int] dd = discrete_distribution[int](values.begin(),values.end())
return dd(gen)

显然,这比均匀分布要复杂一些,但它并不是不可能复杂(并且令人讨厌的部分可能隐藏在 Cython 函数中)。

关于multithreading - 在 Cython 中生成随机数的规范方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40976880/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com