是boost::random::uniform_real_distribution应该在处理器之间是相同的
is boost::random::uniform_real_distribution supposed to be the same across processors?
以下代码在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)
之后,它们的状态数组是相同的。
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- #定义c-预处理器常量..我做错了什么
- int(c) 和 c-'0' 之间的区别。C++
- 预处理器:插入结构名称中的前一个行号
- 如何在c++中实现处理器调度模拟器
- 在cuda线程之间共享大量常量数据
- 在c代码之间共享数据的最佳方式
- Mix_Init和Mix_OpenAudio SDL之间的区别是什么
- C++ 使用 assign 函数的字符串与直接使用 '=' 更改值的字符串之间的区别
- VSOMEIP-2个设备之间的通信(TCP/UDP)不工作
- std::atomic和std::condition_variable wait,notify_*方法之间的区别
- 大小相等但成员数量不同的结构之间的性能差异
- 警告MSB3270:项目的处理器体系结构之间的不匹配
- 关于预处理器保护C和C++之间的公共标头
- 如何使用某些MPI命令(或组合命令)之间在两个处理器之间交换2D数组中存储的数据
- 在 32 位 Linux 机器中生成的预处理器指令列表与为 64 位 Linux 机器生成的预处理器指令列表之间是否有区
- 是boost::random::uniform_real_distribution应该在处理器之间是相同的
- 为什么这个用于在c++ 11和TR1之间切换的预处理器宏不能工作?
- 预处理器和编译器之间的边界到底在哪里?
- 使用预处理器定义在一组类型之间进行选择