boost :: random :: uniform_real_distribution应该是跨处理器的相同吗?

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)

Pet*_*des 6

顺便说一句,您可以编写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.(的单精度增加了双精度在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).