Cython - 使用 stdlib <random>
Cython - using stdlib <random>
我正在尝试使用以下代码使 c++ 库与 cython 一起工作:生成随机数生成器的父项和使用它生成均匀分布的随机数的子项。
[rnd.pyx]
cdef extern from "<random>" namespace "std":
cdef cppclass mt19937:
mt19937() except +
mt19937(unsigned int) except +
cdef cppclass uniform_real_distribution[T]:
uniform_real_distribution()
uniform_real_distribution(double, double)
T operator()(mt19937)
cdef class Child:
cdef mt19937 *rng
cdef uniform_real_distribution[double] uniform
def __cinit__(Child self):
cdef unsigned int seed = 123154654
self.rng = NULL
self.uniform = uniform_real_distribution[double](0.,1.)
cdef set_rng(Child self, mt19937 rng):
self.rng = &rng
def gen_uniform(self):
return self.uniform(self.rng[0])
cdef class Parent:
cdef mt19937 rng
cdef public list children
def __cinit__(Parent self):
cdef unsigned int seed = 123154654
self.rng = mt19937(seed)
self.children = []
cpdef make_child(Parent self):
child = Child()
child.set_rng(self.rng)
self.children.append(child)
[rnd.pyxbuild]
import os
from distutils.extension import Extension
dirname = os.path.dirname(__file__)
def make_ext(modname, pyxfilename):
return Extension(
name=modname,
sources=[pyxfilename],
extra_compile_args=["-std=c++11"],
language="c++",
include_dirs=[dirname]
)
[test.py]
import pyximport
pyximport.install()
from rnd import Child, Parent
p = Parent()
for i in range(300):
p.make_child()
for child in p.children:
a = child.gen_uniform()
print(a)
然而,尽管代码编译正确,gen_uniform
函数的输出确实不是我所期望的:test.py
代码首先生成 0.941197317223,然后永远生成 0.743410046664。
此外,虽然我无法重现它,但我改变了 Child.gen_uniform
,我曾经设法获得(远)大于 1.0
的随机数
最终在一个更复杂的代码中,我将 rng
指针从一个 class 传递给另一个,我得到了正常数字、零、大于一的数字,然后是分段错误。
谁能告诉我问题出在哪里?
您的代码
cdef set_rng(Child self, mt19937 rng):
self.rng = &rng
通过复制传递给它的随机数生成器来创建一个临时随机数生成器 (rng
)。它接受一个指向临时的指针,然后临时在函数结束时不复存在,使指针无效。
您可能想做的是:
cdef set_rng(Child self, mt19937& rng):
self.rng = &rng
(即通过引用传递)。这依赖于 Parent
拥有 Child
和随机数生成器这一事实,所有 Child
都持有指向它的指针。因此,它们都具有相同的寿命。如果这不是真的那么你就有麻烦了,需要重新考虑这个方案(也许考虑共享指针?)。
我正在尝试使用以下代码使 c++ 库与 cython 一起工作:生成随机数生成器的父项和使用它生成均匀分布的随机数的子项。
[rnd.pyx]
cdef extern from "<random>" namespace "std":
cdef cppclass mt19937:
mt19937() except +
mt19937(unsigned int) except +
cdef cppclass uniform_real_distribution[T]:
uniform_real_distribution()
uniform_real_distribution(double, double)
T operator()(mt19937)
cdef class Child:
cdef mt19937 *rng
cdef uniform_real_distribution[double] uniform
def __cinit__(Child self):
cdef unsigned int seed = 123154654
self.rng = NULL
self.uniform = uniform_real_distribution[double](0.,1.)
cdef set_rng(Child self, mt19937 rng):
self.rng = &rng
def gen_uniform(self):
return self.uniform(self.rng[0])
cdef class Parent:
cdef mt19937 rng
cdef public list children
def __cinit__(Parent self):
cdef unsigned int seed = 123154654
self.rng = mt19937(seed)
self.children = []
cpdef make_child(Parent self):
child = Child()
child.set_rng(self.rng)
self.children.append(child)
[rnd.pyxbuild]
import os
from distutils.extension import Extension
dirname = os.path.dirname(__file__)
def make_ext(modname, pyxfilename):
return Extension(
name=modname,
sources=[pyxfilename],
extra_compile_args=["-std=c++11"],
language="c++",
include_dirs=[dirname]
)
[test.py]
import pyximport
pyximport.install()
from rnd import Child, Parent
p = Parent()
for i in range(300):
p.make_child()
for child in p.children:
a = child.gen_uniform()
print(a)
然而,尽管代码编译正确,gen_uniform
函数的输出确实不是我所期望的:test.py
代码首先生成 0.941197317223,然后永远生成 0.743410046664。
此外,虽然我无法重现它,但我改变了 Child.gen_uniform
,我曾经设法获得(远)大于 1.0
最终在一个更复杂的代码中,我将 rng
指针从一个 class 传递给另一个,我得到了正常数字、零、大于一的数字,然后是分段错误。
谁能告诉我问题出在哪里?
您的代码
cdef set_rng(Child self, mt19937 rng):
self.rng = &rng
通过复制传递给它的随机数生成器来创建一个临时随机数生成器 (rng
)。它接受一个指向临时的指针,然后临时在函数结束时不复存在,使指针无效。
您可能想做的是:
cdef set_rng(Child self, mt19937& rng):
self.rng = &rng
(即通过引用传递)。这依赖于 Parent
拥有 Child
和随机数生成器这一事实,所有 Child
都持有指向它的指针。因此,它们都具有相同的寿命。如果这不是真的那么你就有麻烦了,需要重新考虑这个方案(也许考虑共享指针?)。