【问题标题】:Pseudo-random number generation in MEX CMEX C 中的伪随机数生成
【发布时间】:2014-06-24 19:20:13
【问题描述】:

根据定义,函数srand(seed)rand() 使用的随机数生成器提供种子。如果不调用,则根据the documentation,默认种子为1。考虑以下 MEX 代码test.c

#include "mex.h"
#include <stdlib.h>

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
{
    srand(1);
    mexPrintf("%lf\n",(double)rand()/(double)RAND_MAX);
}

从 Matlab 调用时总是返回相同的随机数:

>> mex test.c
>> test
0.001251
>> test
0.001251
>> test
0.001251

考虑以下代码test2.c,其中srand()在随机数生成之前没有被调用:

#include "mex.h"
#include <stdlib.h>

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
{
    mexPrintf("%lf\n",(double)rand()/(double)RAND_MAX);
}

此代码在第一次调用时返回相同的随机数,但每次后续调用返回不同的数字:

>> mex test2.c
>> test2
0.001251
>> test2
0.563585
>> test2
0.193304

鉴于srand() 的默认行为,我不明白为什么省略srand(1) 会在每次调用时产生不同的随机数。事实上,在 Matlab 之外编译和运行test2.c(使用printf 代替mexPrintfint main() 代替void mexFunction(...) 等)总是返回相同的随机数,正如预期的那样。

为什么 MEX 会这样?

【问题讨论】:

  • 也许您已经知道这一点,但是使用“内置”随机数生成器,例如 randiranddrand48,几乎总是一个糟糕的选择——尤其是对于任何科学计算或研究。请参阅规则 #1 here (PDF)。 Matlab 的默认 PRNG,Mersenne TwisterC, C++, and many other languages 中免费提供,而且通常速度更快。
  • @horchler:如果您真的想使用来自 MEX 的 MATLAB 的 Mersenne Twister PRNG,您可以链接到 libmwmathrng.dll 并调用未记录的 C++ 函数 mrRandu(其签名:void mrRandu(double *arr, size_t len);)。这将共享相同的底层 RNG 状态向量,因此调用它将推进 MATLAB 使用的内部随机流。 From what I understand,MATLAB 使用您提到的相同参考实现(仅稍作修改以从 rand 输出中排除零值)
  • 在 DLL libmwmathrng.dll 中当然还有其他版本的这个函数,匹配 rand/randi/randn 的所有变体。只需使用“Dependency Walker”浏览导出的 C/C++ 函数列表。但与任何未记录的函数一样,它不能保证在所有 MATLAB 版本中都保留在那里(我的是 R2014a)。安全(记录在案)的方法是使用 mexCallMATLAB 并从 MATLAB 调用 rand

标签: c matlab random mex standard-library


【解决方案1】:

MEX 文件是在执行时由 MATLAB 动态加载的共享库(具有特殊的入口函数 mexFunction)。除非您清除它们,否则它们会一直加载在内存中。

示例:

最初没有加载 MEX 文件(从另一个工具箱中忽略这个另一个 MEX 文件):

>> [~,X] = inmem('-completenames')
X = 
    'C:\Program Files\MATLAB\R2014a\toolbox\slvnv\reqmgt\reqmgt.mexw64'

现在我们调用 MEX 函数:

>> test2
0.001251
>> test2
0.563585
>> [~,X] = inmem('-completenames')
X = 
    'C:\Program Files\MATLAB\R2014a\toolbox\slvnv\reqmgt\reqmgt.mexw64'
    'C:\Users\Amro\Desktop\test2.mexw64'    % <-- our MEX-file

接下来我们从内存中显式卸载 MEX 函数(clear all 也可以):

>> clear test2
>> [~,X] = inmem('-completenames')
X = 
    'C:\Program Files\MATLAB\R2014a\toolbox\slvnv\reqmgt\reqmgt.mexw64'

当我们现在调用 MEX 函数时,它再次被加载和初始化(再现相同的随机数序列,因为生成器被重置为相同的默认状态):

>> test2
0.001251

【讨论】:

  • 首先,您可以使用 MEX API 中的 mexLock 将 MEX 函数锁定在内存中。只是不要忘记实现一种允许调用相应mexUnlock 的机制(比如一个特殊的输入来指示它,或者使用mexAtExit 注册一个方法)。否则,除非您重新启动 MATLAB 本身,否则您将无法从内存中清除 MEX 文件。
猜你喜欢
  • 2015-08-07
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-18
  • 2012-02-12
  • 1970-01-01
  • 2012-02-09
相关资源
最近更新 更多