OS X libc ++ std :: uniform_real_distribution bug

时间:2016-05-23 03:17:04

标签: c++ c++11 random libc++

我看到一些奇怪的行为使用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 ++中遇到过错误?如果是后者,是否有人知道解决方法?

1 个答案:

答案 0 :(得分:8)

这是LLVM线性同余生成器中的错误,而不是统一的实际分布中的错误。均匀实分布假设发生器返回的数字在发生器的最小值和最大值(包括)之间。这是任何发电机的要求。具有这组数字的LLVM线性同余生成器无法满足该要求。

LLVM线性同余生成器使用旧算法来避免溢出,称为Schrage算法而不是(a*x+c)%m用于您的数字集。该算法的LLVM实现几乎可以保证您的a, c, m集合将生成大于m的数字。

您可以在此处查看LLVM代码:https://llvm.org/svn/llvm-project/libcxx/trunk/include/random。搜索&#39; Schrage的算法&#39;。您选择acm会调用该术语的四次出现中的第一次。

顺便说一下,你的代码中也存在一个错误。那些神奇的数字273673163155和13应该是基数8.这些是drand48使用的数字。随机选择acm的值几乎肯定会导致错误的随机数生成器。

我建议切换为std::mt19937std::mt19937_64