【问题标题】:how to use std::generate_canonical to generate random number in range [0,1)?如何使用 std::generate_canonical 生成 [0,1) 范围内的随机数?
【发布时间】:2013-12-15 06:12:19
【问题描述】:

我在尝试使用 std::generate_canonical 时遇到了问题。根据我在cpp-reference.com 的阅读,我希望std::generate_canonical 生成范围为[0,1) 的数字。 但是,在最新的 MSVC 2012(未安装 CTP)上,std::generate_canonical 生成的数字都是 10^28 的顺序(见下文)。事实上,Microsoft's documentation 并没有提到std::generate_canonical 生成数字的范围。

微软不遵守这里的标准吗?还是标准的不足之处在于它对std::generate_canonical 的行为含糊不清?在第二种情况下,我将如何编写代码来生成 [0,1) 范围内的随机浮点数?

我尝试使用std::generate_canonical,请考虑以下示例代码。

#include <random>
#include <limits>
#include <iostream>

int main(int argc, char* argv[])
{
    std::random_device rd;
    // seed with true source of randomness
    std::mt19937 _rng_generator(rd());

    for(int n=0; n<10; ++n)
        std::cout << std::generate_canonical<double,std::numeric_limits<double>::digits>(_rng_generator) << ' ';

    return EXIT_SUCCESS;
}

我得到的输出示例:
4.85267e+028 2.76741e+028 3.17392e+028 5.84136e+028 1.0037e+028 4.87202e+028 2.53834e+028 4.233e+028 6.43922e+028 2.30694e+028

更新: 我之前已将该错误报告给Microsoft Connect。该错误现已修复,该修复将包含在 MSVC 2014 RTM 中。

【问题讨论】:

  • 我在 Linux 中使用 G++ 4.8 编译了它,它产生了 10 个 [0,1) 范围内的随机数。我不知道微软对你做了什么。
  • Visual Studio 2013 也会生成虚假值。 uniform_real_distribution 可能会满足您的需求。
  • @RetiredNinja。事实上,使用uniform_real_distribution 将是目前的解决方案。

标签: c++ visual-c++ c++11


【解决方案1】:

26.5.7.2 函数模板 generate_canonical [rand.util.canonical]

从本节中描述的模板实例化的每个函数 26.5.7.2 将提供的统一随机数生成器g 的一次或多次调用的结果映射到指定的一个成员 RealType 这样,如果 g 产生的值 gi 是一致的 分布式,实例化的结果tj, 0 ≤ tj

template<class RealType, size_t bits, class URNG> 
RealType generate_canonical(URNG& g);

此外,标准还描述,此函数返回 ,其中

所以,这个函数应该返回一个从零到一的值。我认为,微软的实现在这里是错误的。

【讨论】:

【解决方案2】:

你所指的cpp reference目前说:

“一些现有的实现有一个错误,如果 RealType 是 float GCC #63176 LLVM #18767,它们可能偶尔会返回 1.0。这是 LWG 问题 2524”

根据issue,“问题是标准规定了实现,实现不了。”

问题于 2015 年 8 月 20 日开放,在您发布此问题几年后。

【讨论】:

    【解决方案3】:

    这是 MSDN 文档:

    http://msdn.microsoft.com/en-us/library/ee462289.aspx

    下面是对应的原型:

    template<class RealType,
        size_t bits,
        class Engine>
        RealType generate_canonical(Engine& gen);
    

    这是一个完整的例子:

    http://msdn.microsoft.com/en-us/library/bb982398.aspx

    // cl.exe /EHsc /nologo /W4 /MTd
    #include <algorithm>
    #include <array>
    #include <iostream>
    #include <ostream>
    #include <random>
    #include <string>
    #include <vector>
    using namespace std;
    
    template <typename C> void print(const C& c) {
        for (const auto& e : c) {
            cout << e << " ";
        }
    
        cout << endl;
    }
    
    void test(unsigned int seed) {
        cout << "Seed: " << seed << endl;
    
        mt19937 engine(seed);
    
        uniform_int_distribution<int> dist(-3, 5);
    
        vector<int> v;
    
        for (int i = 0; i < 30; ++i) {
            v.push_back(dist(engine));
        }
    
        cout << "Randomized vector: ";
        print(v);
    
        array<string, 26> arr = { { "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
            "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc",
            "Ti", "V", "Cr", "Mn", "Fe" } };
    
        shuffle(arr.begin(), arr.end(), engine);
    
        cout << "Randomized array: ";
        print(arr);
    }
    
    int main() {
        cout << "--" << endl;
    
        test(12345);
    
        cout << "--" << endl;
    
        random_device rd;
    
        test(rd());
    }
    

    【讨论】:

    • 这是原始问题中给出的链接。这不能解释为什么 MSVC++ 没有产生预期范围 [0,1) 内的值。
    • 好的,我看到您的编辑带有一个详尽的示例,但仍然没有解决为什么 generate_canonical 没有产生预期的结果。您的示例甚至没有使用 generate_canonical。你读的和我一样的问题吗?
    猜你喜欢
    • 2015-10-10
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 2015-08-27
    • 1970-01-01
    • 1970-01-01
    • 2014-01-29
    相关资源
    最近更新 更多