gpt4 book ai didi

C++11 交叉编译器/标准库随机分布再现性

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:21:26 25 4
gpt4 key购买 nike

虽然随机引擎需要在每个编译器上给出相同的数字序列。至少有一些随机分布不是,只要求它们满足统计和概率阈值。例如:

#include <random>
#include <iostream>

int main() {
std::mt19937 foo;
std::uniform_int_distribution<int> bar(0, 1000);

for (int i=0; i<99; ++i) {
bar(foo);
}

std::cout << bar(foo) << std::endl;

return 0;
}

针对(我的版本)libstdc++ 编译时将打印 808,针对 libc++ 编译时将打印 89。

无论给定什么样的合规环境,哪个标准提供的分布函数(如果有的话)都能保证产生一致的结果?

最佳答案

不幸的是,从 N3936(C++14 最终草案)开始,没有提供随机分布的标准有这样的要求。很容易看出原因。有许多编写分布函数的有效方法。有些比其他的好。甚至像正态分布这样基本的东西的算法也越来越好,并且是积极研究的主题。强制使用单个算法会不必要地阻碍 future 算法的实现。

幸运的是,您可以自己编写。各种分发类的 header 规范位于 §26.5.8 下。但是,您没有理由必须遵循这种结构。

(请注意,我没有彻底测试过这段代码,某些引擎可能会出现不良行为,或者溢出,尽管我已经付出了一些努力来避免后者,这更多的是作为一个说明性的例子,而不是一个令人敬畏的均匀分布的规范来源。话虽这么说,如果你发现它有任何问题,请在评论中告诉我,我很乐意纠正它。)

#include <random>
#include <tuple>
#include <iostream>

template<class IntType = int>
class my_uniform_int_distribution {
public:
// types
typedef IntType result_type;
typedef std::pair<int, int> param_type;

// constructors and reset functions
explicit my_uniform_int_distribution(IntType a = 0, IntType b = std::numeric_limits<IntType>::max());
explicit my_uniform_int_distribution(const param_type& parm);
void reset();

// generating functions
template<class URNG>
result_type operator()(URNG& g);
template<class URNG>
result_type operator()(URNG& g, const param_type& parm);

// property functions
result_type a() const;
result_type b() const;
param_type param() const;
void param(const param_type& parm);
result_type min() const;
result_type max() const;

private:
typedef typename std::make_unsigned<IntType>::type diff_type;

IntType lower;
IntType upper;
};

template<class IntType>
my_uniform_int_distribution<IntType>::my_uniform_int_distribution(IntType a, IntType b) {
param({a, b});
}

template<class IntType>
my_uniform_int_distribution<IntType>::my_uniform_int_distribution(const param_type& parm) {
param(parm);
}

template<class IntType>
void my_uniform_int_distribution<IntType>::reset() {}

template<class IntType>
template<class URNG>
auto my_uniform_int_distribution<IntType>::operator()(URNG& g) -> result_type {
return operator()(g, param());
}

template<class IntType>
template<class URNG>
auto my_uniform_int_distribution<IntType>::operator()(URNG& g, const param_type& parm) -> result_type {
diff_type diff = (diff_type)parm.second - (diff_type)parm.first + 1;
if (diff == 0) // If the +1 overflows we are using the full range, just return g()
return g();

diff_type badDistLimit = std::numeric_limits<diff_type>::max() / diff;
do {
diff_type generatedRand = g();

if (generatedRand / diff < badDistLimit)
return (IntType)((generatedRand % diff) + (diff_type)parm.first);
} while (true);
}

template<class IntType>
auto my_uniform_int_distribution<IntType>::a() const -> result_type {
return lower;
}

template<class IntType>
auto my_uniform_int_distribution<IntType>::b() const -> result_type {
return upper;
}

template<class IntType>
auto my_uniform_int_distribution<IntType>::param() const -> param_type {
return {lower, upper};
}

template<class IntType>
void my_uniform_int_distribution<IntType>::param(const param_type& parm) {
std::tie(lower, upper) = parm;
if (upper < lower)
throw std::exception();
}

template<class IntType>
auto my_uniform_int_distribution<IntType>::min() const -> result_type {
return lower;
}

template<class IntType>
auto my_uniform_int_distribution<IntType>::max() const -> result_type {
return upper;
}

int main() {
std::mt19937 foo;
my_uniform_int_distribution<int> bar(0,1000);

for (int i=0; i<99; ++i) {
bar(foo);
}

std::cout << bar(foo) << std::endl;

return 0;
}

此代码在我测试过的所有平台上打印出 490。

关于C++11 交叉编译器/标准库随机分布再现性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42084074/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com