don*_*ght 3 c++ random x86 boost
以下代码在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';
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,您可以编写boost::mt19937 gen(4294653137UL); 以避免在默认构造函数中使用默认种子(5489)进行种子设定.您的代码必须遍历uint32_t生成器内部状态的所有624个元素两次.
发电机总是很好,在任何机器上都能正常工作.区别仅在于使用浮点将其映射到a uniform_real_distribution.
g++ -m32 -msse2 -mfpmath=sse产生与所有其他编译器相同的输出.32对64位是不同的,因为64位使用SSE进行浮点运算,所以double临时值总是64位.32位x86默认使用传统的x87 FPU,其中一切都是内部80位,并且double在存储到内存时仅向下舍入到64位.
请注意,即使在同一平台上,也不能保证使用不同编译器的位相同的FP结果.
32位clang默认仍然使用SSE数学,因此它得到的结果与64bit clang或64bit g ++相同.告诉g ++做同样的事情可以解决问题. -mfpmath=sse告诉它用SSE进行计算(虽然它不会改变ABI,所以浮点返回值仍然在x87中st(0).) -msse2告诉g ++假设目标机器支持SSE和SSE2.(sse2为sse的单精度增加了双精度.SSE2在x86-64架构中是基线,用于在64位ABI中传递/返回FP args.)
如果没有SSE,您可以(但不)使用-ffloat-store精确遵循C标准并通过存储和重新加载它们将中间结果舍入到32或64位.这为每个FP数学指令增加了大约6个周期的延迟.(与Intel Haswell上的3个循环FP add,5个循环FP mul相比.)所以不要这样做,你会得到可怕的代码.
调试步骤:我在Ubuntu 15.10上试用了g ++ 5.2,clang-3.5和clang-3.8(来自http://llvm.org/apt/).
for i in ./boost-random-seedint*; do echo -ne "$i:\t" ; $i|md5sum ;done
./boost-random-seedint-g++32: 53d99523ca2afeac428eae2c89e69974 -
./boost-random-seedint-g++64: a59f08c0bc22b8753c474db077b809bd -
./boost-random-seedint-clang3.5-32: a59f08c0bc22b8753c474db077b809bd -
./boost-random-seedint-clang3.5-64: a59f08c0bc22b8753c474db077b809bd -
./boost-random-seedint-clang3.8-32: a59f08c0bc22b8753c474db077b809bd -
./boost-random-seedint-clang3.8-64: a59f08c0bc22b8753c474db077b809bd -
Run Code Online (Sandbox Code Playgroud)
所以唯一的异常值是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
Run Code Online (Sandbox Code Playgroud)
铿锵没有-Og.带有-O0和-O3的32位g ++使二进制文件的输出与输出的二进制文件相同-Og.
调试32位和64位二进制文件:它们的状态数组在默认种子之后和调用之后是相同的gen.seed(4294653137UL).