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

时间:2015-11-09 23:09:53

标签: c++ random generator

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

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

3 个答案:

答案 0 :(得分:10)

更新第二项实施已添加到

之下

如果你想使这个通用,你将不得不编码。

有两种选择:

  • discrete_distribution(只是喂它5,6,7,10,11,12)
  • 生成数字[0..6]并索引到数组int arr[]={5,6,7,10,11,12}

第二个:

<强> Live On Coliru

#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)] << " ";
}

打印

5 5 6 12 11 6 11 12 5 12 

或者,当然类似

更新

通过使用Boost Interval Container Library有效地表示构成域的间隔,可以扩展许多段或大段的替代实现:

<强> Live On Coliru

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>?
};

像往常一样使用它:

mt19937 mt { random_device {} () };

uniform_draw<int> dist { {5, 7}, {10, 12} };

std::cout << dist << "\n";

for (int i = 0; i < 10; ++i)
    std::cout << "RESULT: " << dist(mt) << "\n";

打印例如:

{[5,7)[10,12)} (#samples:4)
7 7 6 11 6 6 7 7 7 6 

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

我看到两种方法可以做到这一点。让我们说你的两个范围是[minA,maxA]和[minB,maxB],其中maxA&lt; minB(如果不只是交换两个范围)

解决方案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) generate a random number X within [0,rangeA+rangeB]
3) if X < rangeA then output minA+X else minB+X