OS X libc++ std::uniform_real_distribution 错误
OS X libc++ std::uniform_real_distribution bug
我在使用 C++ 11 std::uniform_real_distribution
Apple LLVM 版本 7.0.2 (clang-700.1.81) 编译时看到了一些奇怪的行为。调用 operator() 会呈现超出分布范围的结果。下面的最小示例程序重现了问题
// Example program
#include <random>
#include <iostream>
#include <string>
template< int power >
constexpr uint64_t power_of_two(){
return 2 * power_of_two< power - 1 >();
}
template< >
constexpr uint64_t power_of_two< 0 >(){
return 1;
}
std::linear_congruential_engine
< uint64_t, 273673163155, 13, power_of_two< 48 >() >
rng;
std::uniform_real_distribution< double > angle_cosine(-1, 1);
int main()
{
std::cout << angle_cosine.a() << " " << angle_cosine.b() << '\n' << std::endl;
for (int i = 0; i < 4; ++i){
std::cout << angle_cosine(rng) << std::endl;
}
}
编译和 运行 online(大概是用 g++)呈现合理的结果
-1 1
-0.529254
-0.599452
0.513316
-0.604338
但是,编译和 运行 本地呈现不合理的结果。
-1 1
130349
37439.4
42270.5
45335.4
我是否忽略了什么或者我是否遇到了 libc++ 中的错误?如果是后者,有人知道解决方法吗?
这是 LLVM 线性同余生成器中的错误,而不是均匀实数分布中的错误。均匀实数分布假定生成器返回的数字介于生成器的最小值和最大值之间(含)。这是任何生成器的要求。具有这组数字的 LLVM 线性同余生成器无法满足该要求。
LLVM 线性同余生成器使用称为 Schrage 算法的旧算法来避免溢出,而不是 (a*x+c)%m
用于您的数字集。该算法的 LLVM 实现实际上保证了您的 a, c, m
集将生成大于 m
.
的数字
您可以在此处查看 LLVM 代码:https://llvm.org/svn/llvm-project/libcxx/trunk/include/random。搜索“施拉格算法”。您对 a
、c
和 m
的选择调用了该术语四次出现中的第一次。
顺便说一句,您的代码中也有错误。那些幻数 273673163155 和 13 应该是以 8 为底数。这些是 drand48
使用的数字。随机选择 a
、c
和 m
的值几乎肯定会导致错误的随机数生成器。
我建议切换到 std::mt19937
或 std::mt19937_64
。
我在使用 C++ 11 std::uniform_real_distribution
Apple LLVM 版本 7.0.2 (clang-700.1.81) 编译时看到了一些奇怪的行为。调用 operator() 会呈现超出分布范围的结果。下面的最小示例程序重现了问题
// Example program
#include <random>
#include <iostream>
#include <string>
template< int power >
constexpr uint64_t power_of_two(){
return 2 * power_of_two< power - 1 >();
}
template< >
constexpr uint64_t power_of_two< 0 >(){
return 1;
}
std::linear_congruential_engine
< uint64_t, 273673163155, 13, power_of_two< 48 >() >
rng;
std::uniform_real_distribution< double > angle_cosine(-1, 1);
int main()
{
std::cout << angle_cosine.a() << " " << angle_cosine.b() << '\n' << std::endl;
for (int i = 0; i < 4; ++i){
std::cout << angle_cosine(rng) << std::endl;
}
}
编译和 运行 online(大概是用 g++)呈现合理的结果
-1 1
-0.529254
-0.599452
0.513316
-0.604338
但是,编译和 运行 本地呈现不合理的结果。
-1 1
130349
37439.4
42270.5
45335.4
我是否忽略了什么或者我是否遇到了 libc++ 中的错误?如果是后者,有人知道解决方法吗?
这是 LLVM 线性同余生成器中的错误,而不是均匀实数分布中的错误。均匀实数分布假定生成器返回的数字介于生成器的最小值和最大值之间(含)。这是任何生成器的要求。具有这组数字的 LLVM 线性同余生成器无法满足该要求。
LLVM 线性同余生成器使用称为 Schrage 算法的旧算法来避免溢出,而不是 (a*x+c)%m
用于您的数字集。该算法的 LLVM 实现实际上保证了您的 a, c, m
集将生成大于 m
.
您可以在此处查看 LLVM 代码:https://llvm.org/svn/llvm-project/libcxx/trunk/include/random。搜索“施拉格算法”。您对 a
、c
和 m
的选择调用了该术语四次出现中的第一次。
顺便说一句,您的代码中也有错误。那些幻数 273673163155 和 13 应该是以 8 为底数。这些是 drand48
使用的数字。随机选择 a
、c
和 m
的值几乎肯定会导致错误的随机数生成器。
我建议切换到 std::mt19937
或 std::mt19937_64
。