gpt4 book ai didi

使用浮点精度时,C++ 随机为相同的 Mersenne Twister 种子产生不同的数字

转载 作者:可可西里 更新时间:2023-11-01 16:35:22 27 4
gpt4 key购买 nike

我需要运行可重现的蒙特卡洛运行。这意味着我使用与我的结果一起存储的已知种子,如果我需要使用相同的随机数运行相同的问题实例,则使用该种子。这是常见的做法。

在研究数值精度的影响时,我遇到了以下问题:对于同一个 Mersenne Twister 种子,std::uniform_real_distribution<float>(-1, 1)返回与 std::uniform_real_distribution<double>(-1, 1) 不同的数字和 std::uniform_real_distribution<long double>(-1, 1) ,如以下示例所示:

#include <iomanip>
#include <iostream>
#include <random>

template < typename T >
void numbers( int seed ) {
std::mt19937 gen( seed );
std::uniform_real_distribution< T > dis( -1, 1 );
auto p = std::numeric_limits< T >::max_digits10;
std::cout << std::setprecision( p ) << std::scientific << std::setw( p + 7 )
<< dis( gen ) << "\n"
<< std::setw( p + 7 ) << dis( gen ) << "\n"
<< std::setw( p + 7 ) << dis( gen ) << "\n"
<< "**********\n";
}

int main() {
int seed = 123;
numbers< float >( seed );
numbers< double >( seed );
numbers< long double >( seed );
}

结果:

$ /usr/bin/clang++ -v
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

$ /usr/bin/clang++ bug.cpp -std=c++17
$ ./a.out
3.929383755e-01
4.259105921e-01
-4.277213216e-01
**********
4.25910643160561708e-01
-1.43058149942132062e-01
3.81769702875451866e-01
**********
4.259106431605616525145e-01
-1.430581499421320209545e-01
3.817697028754518623166e-01
**********

如您所见,doublelong double两者都从相同的数字开始(保留精度差异)并继续产生相同的值。另一方面,float以一个完全不同的数字开始,它的第二个数字与 double 生成的第一个数字相似和 long double .

您是否在编译器中看到相同的行为?这种(对我来说)出乎意料的差异是否有原因?

方法

回复清楚地表明,没有理由期望以不同的基础精度生成的值会相同。

我将采用生成可重现运行的方法是始终以尽可能高的精度生成值,并根据需要将它们转换为较低的精度(例如,float x = y,其中 ydoublelong double ,视情况而定)。

最佳答案

每个分布将通过从底层 Mersenne Twister 中获取足够数量的(伪)随机位然后从中生成均匀分布的 float 来生成 float 。

只有两种实现方式可以满足您对“相同算法,因此结果相同(减去精度)”的期望:

  1. std::uniform_real_distribution<long double>(-1, 1)仅与 std::uniform_real_distribution<float>(-1, 1) 一样随机.更重要的是,前者与后者具有完全一样多的可能输出。如果后者可以产生比前者更多不同的值,那么它需要从底层 Mersenne Twister 消耗更多的随机性位。如果它不能 - 那么,使用它有什么意义(以及它如何仍然是“统一的”)?

  2. std::uniform_real_distribution<float>(-1, 1)从底层 Mersenne Twister 中消耗(并且大部分丢弃)与 std::uniform_real_distribution<long double>(-1, 1) 一样多的随机性位。 .那将是非常浪费和低效的。

由于没有理智的实现会执行上述任一操作,std::uniform_real_distribution<long double>(-1, 1)将以比 std::uniform_real_distribution<float>(-1, 1) 更多的步数推进底层 Mersenne Twister对于每个生成的数字。这当然会改变随机数的进程。这也解释了为什么 long doubledouble variant 相对靠近:它们最初共享大部分随机位(而 float 可能需要更少的位,因此发散更快)。

关于使用浮点精度时,C++ 随机为相同的 Mersenne Twister 种子产生不同的数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53523687/

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