C++ 在C++;,如何生成介于两个范围之间的随机数?

C++ 在C++;,如何生成介于两个范围之间的随机数?,c++,random,generator,C++,Random,Generator,如何编写代码来生成介于两个不同范围之间的随机数 示例:生成介于5和7之间或介于10和12之间的随机数。可能的结果是5、6、7、10、11或12。更新下面添加了第二次实施 如果你想让它通用,你必须对它进行编码 我想到两个选择: 离散分布(只需输入5,6,7,10,11,12) 生成数字[0..6)并索引到数组int arr[]={5,6,7,10,11,12} 第二点: #include <random> #include <iostream> int main(

如何编写代码来生成介于两个不同范围之间的随机数

示例:生成介于5和7之间或介于10和12之间的随机数。可能的结果是5、6、7、10、11或12。

更新下面添加了第二次实施


如果你想让它通用,你必须对它进行编码

我想到两个选择:

  • 离散分布(只需输入5,6,7,10,11,12)
  • 生成数字[0..6)并索引到数组
    int arr[]={5,6,7,10,11,12}
第二点:

#include <random>
#include <iostream>

int main()
{
    using namespace std;
    vector<int> arr = {5,6,7,10,11,12};

    mt19937 prng { random_device {} () };
    uniform_int_distribution<> dist(0, arr.size()-1);

    int i = 10;
    while (i--)
        std::cout << arr[dist(prng)] << " ";
}
template <typename T = int>
struct uniform_draw {

    using set  = boost::icl::interval_set<T>;
    using ival = typename set::interval_type::type;

    uniform_draw(std::initializer_list<ival> data) 
        : set_(make_set(data)), dist_(0, set_.size() - 1)
    { }

    friend std::ostream& operator<<(std::ostream& os, uniform_draw const& ud) {
        return os << ud.set_ << " (#samples:" << ud.set_.size() << ")";
    }

    template <typename Engine>
    T operator()(Engine& engine) {
        uintmax_t index = dist_(engine);

        std::cout << " - index: " << index << " against " << set_ << "\n";

        // I think this can be optimized. I just don't know how to elegantly do that / yet
        for (auto& iv : set_) {
            std::cout << " - index: " << index << " against " << iv << "\n";
            if (index > size(iv)) {
                index -= size(iv);
            } else {
                return iv.lower() + index;
            }
        }

        throw std::range_error("uniform_draw");
    }

private:
    set make_set(std::initializer_list<ival> data) {
        set r;
        for (auto& el : data)
            r.insert(el);
        return r;
    }

    set const set_;
    std::uniform_int_distribution<T> dist_; // TODO make_unsigned<T>?
};
或者,当然类似


更新 通过使用Boost Interval容器库有效地表示构成域的间隔,可扩展为多段或大段的替代实现:

#include <random>
#include <iostream>

int main()
{
    using namespace std;
    vector<int> arr = {5,6,7,10,11,12};

    mt19937 prng { random_device {} () };
    uniform_int_distribution<> dist(0, arr.size()-1);

    int i = 10;
    while (i--)
        std::cout << arr[dist(prng)] << " ";
}
template <typename T = int>
struct uniform_draw {

    using set  = boost::icl::interval_set<T>;
    using ival = typename set::interval_type::type;

    uniform_draw(std::initializer_list<ival> data) 
        : set_(make_set(data)), dist_(0, set_.size() - 1)
    { }

    friend std::ostream& operator<<(std::ostream& os, uniform_draw const& ud) {
        return os << ud.set_ << " (#samples:" << ud.set_.size() << ")";
    }

    template <typename Engine>
    T operator()(Engine& engine) {
        uintmax_t index = dist_(engine);

        std::cout << " - index: " << index << " against " << set_ << "\n";

        // I think this can be optimized. I just don't know how to elegantly do that / yet
        for (auto& iv : set_) {
            std::cout << " - index: " << index << " against " << iv << "\n";
            if (index > size(iv)) {
                index -= size(iv);
            } else {
                return iv.lower() + index;
            }
        }

        throw std::range_error("uniform_draw");
    }

private:
    set make_set(std::initializer_list<ival> data) {
        set r;
        for (auto& el : data)
            r.insert(el);
        return r;
    }

    set const set_;
    std::uniform_int_distribution<T> dist_; // TODO make_unsigned<T>?
};
更新下面添加了第二个实施


如果你想让它通用,你必须对它进行编码

我想到两个选择:

  • 离散分布(只需输入5,6,7,10,11,12)
  • 生成数字[0..6)并索引到数组
    int arr[]={5,6,7,10,11,12}
第二点:

#include <random>
#include <iostream>

int main()
{
    using namespace std;
    vector<int> arr = {5,6,7,10,11,12};

    mt19937 prng { random_device {} () };
    uniform_int_distribution<> dist(0, arr.size()-1);

    int i = 10;
    while (i--)
        std::cout << arr[dist(prng)] << " ";
}
template <typename T = int>
struct uniform_draw {

    using set  = boost::icl::interval_set<T>;
    using ival = typename set::interval_type::type;

    uniform_draw(std::initializer_list<ival> data) 
        : set_(make_set(data)), dist_(0, set_.size() - 1)
    { }

    friend std::ostream& operator<<(std::ostream& os, uniform_draw const& ud) {
        return os << ud.set_ << " (#samples:" << ud.set_.size() << ")";
    }

    template <typename Engine>
    T operator()(Engine& engine) {
        uintmax_t index = dist_(engine);

        std::cout << " - index: " << index << " against " << set_ << "\n";

        // I think this can be optimized. I just don't know how to elegantly do that / yet
        for (auto& iv : set_) {
            std::cout << " - index: " << index << " against " << iv << "\n";
            if (index > size(iv)) {
                index -= size(iv);
            } else {
                return iv.lower() + index;
            }
        }

        throw std::range_error("uniform_draw");
    }

private:
    set make_set(std::initializer_list<ival> data) {
        set r;
        for (auto& el : data)
            r.insert(el);
        return r;
    }

    set const set_;
    std::uniform_int_distribution<T> dist_; // TODO make_unsigned<T>?
};
或者,当然类似


更新 通过使用Boost Interval容器库有效地表示构成域的间隔,可扩展为多段或大段的替代实现:

#include <random>
#include <iostream>

int main()
{
    using namespace std;
    vector<int> arr = {5,6,7,10,11,12};

    mt19937 prng { random_device {} () };
    uniform_int_distribution<> dist(0, arr.size()-1);

    int i = 10;
    while (i--)
        std::cout << arr[dist(prng)] << " ";
}
template <typename T = int>
struct uniform_draw {

    using set  = boost::icl::interval_set<T>;
    using ival = typename set::interval_type::type;

    uniform_draw(std::initializer_list<ival> data) 
        : set_(make_set(data)), dist_(0, set_.size() - 1)
    { }

    friend std::ostream& operator<<(std::ostream& os, uniform_draw const& ud) {
        return os << ud.set_ << " (#samples:" << ud.set_.size() << ")";
    }

    template <typename Engine>
    T operator()(Engine& engine) {
        uintmax_t index = dist_(engine);

        std::cout << " - index: " << index << " against " << set_ << "\n";

        // I think this can be optimized. I just don't know how to elegantly do that / yet
        for (auto& iv : set_) {
            std::cout << " - index: " << index << " against " << iv << "\n";
            if (index > size(iv)) {
                index -= size(iv);
            } else {
                return iv.lower() + index;
            }
        }

        throw std::range_error("uniform_draw");
    }

private:
    set make_set(std::initializer_list<ival> data) {
        set r;
        for (auto& el : data)
            r.insert(el);
        return r;
    }

    set const set_;
    std::uniform_int_distribution<T> dist_; // TODO make_unsigned<T>?
};

选择一个随机数
0
1
。如果该数字为
0
,则在第一个范围内选择一个随机数,否则在第二个范围内选择一个随机数


如果希望两个范围内的每个数字具有相同的概率,可以根据两个范围的大小对第一个决策进行加权。

选择一个随机数
0
1
。如果该数字为
0
,则选择第一个范围内的随机数,否则选择第二个范围内的随机数


如果您希望两个范围内的每个数字具有相等的概率,您可以根据两个范围的大小对第一个决定进行加权。

我看到两种方法。假设您的两个范围是[minA,maxA]和[minB,maxB],其中maxA 解决方案1:

1) Generate a random number X in [minA, maxB] first
2) if X falls (maxA,minB) goto 1)
3) At this point X is the output
解决方案2(特别是当两个范围之间的差距较大时,效率更高):

1)rangeA=maxA-minA,rangeB=maxB-minB;
2) 在[0,rangeA+rangeB]范围内生成一个随机数X
3) 如果X<范围a,则输出minA+X,否则输出minB+X

我看到了两种方法。假设您的两个范围是[minA,maxA]和[minB,maxB],其中maxA 解决方案1:

1) Generate a random number X in [minA, maxB] first
2) if X falls (maxA,minB) goto 1)
3) At this point X is the output
解决方案2(特别是当两个范围之间的差距较大时,效率更高):

1)rangeA=maxA-minA,rangeB=maxB-minB;
2) 在[0,rangeA+rangeB]范围内生成一个随机数X
3) 如果X<范围a,则输出minA+X,否则输出minB+X


只需谷歌搜索“C++随机数范围内”所需时间的一小部分根据您想要的分布类型,有两个选项。例如,您可以生成一个数字来选择您想要的两个范围中的哪一个,然后再生成一个数字来从所选范围中选择一个数字。显然,这可能会使不同大小范围的结果发生偏差。或者:将单独的范围映射到具有“大小”的新范围=总和(基本范围的大小)。为新范围生成一个数字,并将结果映射回一个原始范围。(注意:如果任何范围重叠,结果也可能会倾斜。)评论者似乎很方便地掩盖了不是关于单个范围的细节。所有这些否决票…:(每一个想到这些事情的人都应该好好地看一看专家的精彩演讲:用谷歌搜索“C++随机数在范围内”只需要一小部分时间根据您想要的分布类型,有两个选项。例如,您可以生成一个数字来选择您想要的两个范围中的哪一个,然后再生成一个数字来从所选范围中选择一个数字。显然,这可能会使不同大小范围的结果发生偏差。或者:将单独的范围映射到具有“大小”的新范围=总和(基本范围的大小)。为新范围生成一个数字,并将结果映射回一个原始范围。(注意:如果任何范围重叠,结果也可能会倾斜。)评论者似乎很方便地掩盖了不是关于单个范围的细节。所有这些否决票…:(每一个想到这些事情的人都应该好好看一看专家的精彩演讲:如果范围大小不相等,这将不会导致均匀分布。但是OP没有明确说明这一点,他们只是想随机,所以这将是随机的。这与Jared之前发布(并删除)的答案相同)@A.S.H.我添加了一条关于根据两个范围的大小对第一选择进行加权的评论。我删除了它,因为根据这个答案它是多余的。OP已经为这个问题添加了很多澄清。如果范围大小不相等,这将不会导致均匀分布。但是OP没有明确说明它,不管怎样,它是ey只是想要随机的,所以这将是随机的..这与Jared之前发布(并删除)的答案相同@A.S.H我添加了一条关于根据两个范围的大小对第一选择进行加权的评论。我删除了它,因为根据这个答案它是多余的。OP已经为这个问题添加了很多澄清。这与我即将发布的内容之间的唯一区别是
使用名称空间std;
向量的名称,我对循环使用了一个
。这个答案需要大数组。如果范围太大怎么办?我相信有一个简单的解决方案不需要这样的ar