我尝试使用以下代码使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
指针从一个类传递给另一个类,我得到正常数字,零,大于一个数字,然后是分段错误。
有人能告诉我问题的来源吗?
答案 0 :(得分:2)
您的代码
cdef set_rng(Child self, mt19937 rng):
self.rng = &rng
通过复制传递给它的随机数生成器来创建临时随机数生成器(rng
)。它需要一个指向临时的指针,然后临时不再存在于函数的末尾,导致指针无效。
你可能想做的是:
cdef set_rng(Child self, mt19937& rng):
self.rng = &rng
(即通过引用传递)。这取决于Parent
拥有Child
和随机数生成器这一事实,所有Child
都持有指针。因此,它们都具有相同的寿命。如果这不是真的那么你就麻烦了并且需要重新考虑这个方案(也许考虑共享指针?)。