随机数生成:相同的C++代码,两种不同的行为

Random Number Generation : same C++ code, two different behaviors

本文关键字:两种 代码 C++ 随机数      更新时间:2023-10-16

和我的同事正在C++一起做一个蒙特卡洛项目。她使用Visual Studio,我使用Xcode,我们通过git共享代码。我们正在计算美国期权价格,这要归功于需要随机数生成的给定方法。我们意识到某个参数 K 的结果是错误的(参数越高,答案越错误),我的同事发现将 Mersenne Twister 的随机源更改为 rand()(尽管生成器很差)会使结果对整个 K 范围都有好处。

但是当我更改代码版本的源代码时,它什么也没做。

更让我费解的是,我创建了一个新的 Xcode 项目,在其中复制了她的整个源代码,它仍然给了我错误的结果(而她得到了好的结果)。所以它不能源于代码本身。我清理了项目,重新启动了Xcode,甚至重新启动了我的计算机(...),但没有任何变化:我们的项目行为一致但不同,背后使用相同的代码。(编辑:通过不同但一致的,我并不是说我们没有相同的数字序列。我的意思是她的蒙特卡洛估计器收敛于 4。和我的朝向 3.)

你知道这种双重行为的原因是什么吗?

这是随机生成代码:

double loiuniforme() //uniform law
{
    return (double)((float)rand() / (float)RAND_MAX);
}

vector<double> loinormale() //normal law
{
    vector<double> loinormales(2, 0.);
    double u1 = loiuniforme();
    double v1 = loiuniforme();
    loinormales[0] = sqrt(-2 * log(u1))*cos(2 * M_PI*v1);
    loinormales[1] = sqrt(-2 * log(u1))*sin(2 * M_PI*v1);
    return(loinormales);
}

编辑:之前使用的MT RNG是:

double loiuniforme()
{
    mt19937::result_type seed = clock();
    auto real_rand = std::bind(std::uniform_real_distribution<double>(0,1), mt19937(seed));
    return real_rand();
}

C++ 标准没有指定rand()使用什么算法。编写编译器的人可以自由使用他们想要的任何实现,并且不能保证它在两个不同的编译器、两个不同的体系结构甚至同一编译器的两个不同版本上的行为相同。

您应该只创建一个生成器并将其用于每个数字。

mt19937::result_type seed = clock();

mt19937(seed)

每次调用函数时,都会创建一个具有新种子的新生成器。
这会导致随机性全部扭曲。

您可以在函数中使用静态变量,因为这些变量在第一次调用时初始化:

double loiuniforme() 
{ 
    static std::mt19937 generator(clock()); 
    static std::uniform_real_distribution<double> distribution(0, 1); 
    return distribution(generator); 
}

(当您与同事比较结果时,请使用相同的硬编码种子来验证您是否获得相同的结果。

您需要

在两台计算机上使用相同的编号播种rand函数。 即便如此,我也不确定跨计算机和操作系统的底层代码是否会返回相同的值。

更重要的是,如果你想要相同的结果,不要使用随机函数。