C++ boost::random::uniform\u real\u分布在处理器之间应该是相同的吗?

C++ boost::random::uniform\u real\u分布在处理器之间应该是相同的吗?,c++,random,x86,boost,sse2,sse,C++,Random,X86,Boost,Sse2,Sse,以下代码在x86 32位和64位处理器上生成不同的输出 应该是这样吗?如果我用std::uniform_real_distribution替换它,并用-std=c++11编译,它在两个处理器上产生相同的输出 #include <iostream> #include <boost/random/mersenne_twister.hpp> #include <boost/random/uniform_real_distribution.hpp> int main

以下代码在x86 32位和64位处理器上生成不同的输出

应该是这样吗?如果我用std::uniform_real_distribution替换它,并用-std=c++11编译,它在两个处理器上产生相同的输出

#include <iostream>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_real_distribution.hpp>

int main()
{
    boost::mt19937 gen;
    gen.seed(4294653137UL);
    std::cout.precision(1000);
    double lo = - std::numeric_limits<double>::max() / 2 ;
    double hi = + std::numeric_limits<double>::max() / 2 ;
    boost::random::uniform_real_distribution<double> boost_distrib(lo, hi);
    std::cout << "lo " << lo << '\n';
    std::cout << "hi " << hi << "\n\n";
    std::cout << "boost distrib gen " << boost_distrib(gen) << '\n';
}
#包括
#包括
#包括
int main()
{
增压:mt19937发电机;
种子(4294653137UL);
标准:计算精度(1000);
双lo=-std::numeric_limits::max()/2;
双hi=+std::数值限制::max()/2;
boost::random::uniform\u real\u distrib分布boost\u distrib(lo,hi);

std::coutBTW,您可以编写
boost::mt19937 gen(4294653137UL);
以避免在默认构造函数中使用默认种子(5489)进行种子设定。您的代码必须在生成器内部状态的所有624
uint32
元素上循环两次


生成器总是很好,在任何机器上都可以正常工作。区别只在于使用浮点将其映射到
均匀实分布

g++-m32-msse2-mfpmath=sse
生成与所有其他编译器相同的输出
。32位与64位不同,因为64位使用sse进行浮点运算,所以
double
临时值始终为64位。32位x86默认使用传统的x87 FPU,其中所有内容在内部都是80位,只舍入到64b当存储到内存时,它将
加倍

默认情况下,32位clang仍然使用SSE math,因此它得到与64位clang或64位g++相同的结果。告诉g++这样做可以解决问题。
-mfpmath=SSE
告诉它使用SSE进行计算(虽然它不改变ABI,所以浮点返回值仍然在x87
st(0)
-msse2
告诉g++假设目标机器支持SSE和SSE2。(为的单精度添加了双精度。SSE2是x86-64体系结构中的基线,用于在64位ABI中传递/返回FP args。)

如果没有SSE,您可以(但不要)使用
-ffloat store
精确地遵循C标准,并通过存储和重新加载将中间结果舍入到32或64位。这会给每个FP数学指令增加大约6个周期的延迟(与Intel Haswell上的3个周期FP add、5个周期FP mul相比)所以不要这样做,你会得到可怕的代码


调试步骤: 我在Ubuntu15.10上用g++5.2、clang-3.5和clang-3.8(源代码)进行了测试

所以唯一的异常值是32位g++。所有其他输出都有相同的散列

编译器选项:

clang++-3.8 -m32 -O1 -g boost-random-seedint.cpp -o boost-random-seedint-clang3.8-32  # and similiar
g++ -m32 -Og -g boost-random-seedint.cpp -o boost-random-seedint32
clang没有一个
-Og
.32位的g++和-O0和-O3生成的二进制文件,它们的输出与
-Og
的输出相同



调试32位和64位二进制文件:在默认种子和调用
gen.seed(4294653137UL)

后,它们的状态数组是相同的。您可能会假设使用相同的种子将产生相同的结果。我会将此报告为一个bug以进行增强。我在“可流化概念允许保存/恢复生成器的状态,例如在以后重新运行测试套件。”该表显示了使用
625*sizeof(uint32\t)的mt19937生成器
其状态空间意味着代码使用
uint32\u t
而不考虑平台。您的32位和64位二进制文件是否使用同一版本的Boost?表示从整数开始的种子设定在2005年发生了变化。嗯,不,这并不能解释它,因为我刚刚在您的代码上尝试了
g++-m32
g++
,以及
diff-u g关于它不改变ABI并且仍然使用
st(0)的ood要点
。另外,知道Clang即使在32位模式下也默认为SSE也是很有趣的。我不明白为什么人们仍然谈论x86 32位代码。很多软件仍然是在x86 32位和64位模式下发布的。我不明白为什么。这使得ARM的ARMv7仍然很常见,但对于x86我不明白。@Zboson:我想是因为有些人愚蠢地为可以运行64位的计算机购买了32位windows。或者可能只是因为WinXP还没有死。或者可能他们的代码利用了一些库,而无论出于什么原因,这些库无法以64位重新编译?我的意思是,即使是Skype这样的大型应用程序也只能以32位二进制文件提供,即使是Linux。我完全同意同意你的观点:人们应该停止浪费每个人的时间在传统的32位代码上。有一些方法可以使指针密集型数据结构在64位代码中不臃肿。(例如,存储索引,或在32位低位分配内存)。我一直在思考这个问题有一段时间了。答案是,我所从事的项目的用户都有旧机器。尤其是学校。贫穷州和国家的学校通常都有旧的旧硬件。这就是问题的根源。用户。@donbright:我想问题在于期待FP决定论。这不是问题所在用户的错误—他们运行的是32位软件;平台上的其他一些差异可能会暴露出同样的问题。(如果幸运的话,x87 80位临时值是异常值,ARM或PowerPC会将64位x86的结果与SSE2 math匹配,只要您避免使用诸如
sin()
log()之类的数学库函数)
,因为+-*/和sqrt都需要“正确四舍五入”到最后一个ulp。)
clang++-3.8 -m32 -O1 -g boost-random-seedint.cpp -o boost-random-seedint-clang3.8-32  # and similiar
g++ -m32 -Og -g boost-random-seedint.cpp -o boost-random-seedint32