是boost::random::uniform_real_distribution应该在处理器之间是相同的

is boost::random::uniform_real_distribution supposed to be the same across processors?

本文关键字:之间 处理器 distribution random boost uniform real      更新时间:2023-10-16

以下代码在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 << "nn";
    std::cout << "boost distrib gen " << boost_distrib(gen) << 'n';
}

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


发电机总是很好,在任何机器上都能正常工作。区别仅在于使用浮点将其映射到uniform_real_distribution

g++ -m32 -msse2 -mfpmath=sse生成与所有其他编译器相同的输出。32和64位是不同的,因为64位使用SSE进行浮点运算,所以double临时值总是64位。32位x86默认使用传统的x87 FPU,其中所有内容在内部都是80位,并且在存储到内存时仅四舍五入到64位double

请注意,即使在同一平台上,不同的编译器也不能保证genral中的位完全相同的FP结果

默认情况下,32位clang仍然使用SSE数学,因此它得到的结果与64位clang或64位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  -

因此,唯一的异常值是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)之后,它们的状态数组是相同的。