顺便说一句,你可以写boost::mt19937 gen(4294653137UL);
以避免在默认构造函数中使用默认种子 (5489) 进行播种。你的代码必须遍历所有 624uint32_t
生成器内部状态的元素两次。
发电机总是很好,并且在任何机器上都一样工作。区别仅在于使用浮点将其映射到uniform_real_distribution
.
g++ -m32 -msse2 -mfpmath=sse
为所有其他编译器生成相同的输出。 32 位与 64 位不同,因为 64 位使用 SSE 进行浮点数学运算,因此double
临时文件始终是 64 位。 32 位 x86 默认使用旧版 x87 FPU,内部所有内容都是 80 位,并且仅向下舍入到 64 位double
存储到内存时。
请注意,即使在同一平台上,不同编译器也不能保证位相同的 FP 结果.
32 位 clang 默认情况下仍使用 SSE 数学,因此它获得与 64 位 clang 或 64 位 g++ 相同的结果。告诉 g++ 做同样的事情可以解决问题。-mfpmath=sse
告诉它使用 SSE 进行计算(尽管它不会更改 ABI,因此浮点返回值仍然是 x87st(0)
.) -msse2
告诉 g++ 假设目标机器支持 SSE 和 SSE2。 (sse2添加了双精度sse的单精度。 SSE2 是 x86-64 架构中的基线,用于传递/返回 64 位 ABI 中的 FP 参数。)
没有上证所,你could (but don't) use -ffloat-store
精确遵循 C 标准并通过存储和重新加载中间结果将其舍入为 32 或 64 位。这给每个 FP 数学指令增加了大约 6 个周期的延迟。 (与 Intel Haswell 上的 3 周期 FP add、5 周期 FP mul 相比。)don't这样做,你会得到可怕的代码。
调试步骤:
我在 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
。带有 -O0 和 -O3 的 32 位 g++ 生成的二进制文件与来自的二进制文件具有相同的输出-Og
.
调试 32 位和 64 位二进制文件:在默认种子之后和调用之后,它们的状态数组是相同的gen.seed(4294653137UL)
.