如何使用C ++中的均值生成随机数?

时间:2015-02-15 22:04:57

标签: c++ c++11 random

如何在1,000到20,000之间生成100个随机数,C ++中的平均值为9,000?我正在研究C ++ 11库,但我找不到允许我包含平均值和范围的方法。

5 个答案:

答案 0 :(得分:6)

由于您不关心分布,只要它满足您的约束,到目前为止最简单的方法就是始终只生成9000。最简单的分布就是生成1000概率p20000概率为1-p的东西,其中你已经解决了{{1}的值这给出了正确的平均值。

我强烈怀疑在开始考虑编程之前,你应该弄清楚你要做的事情的数学/统计。

答案 1 :(得分:6)

由于您在分发方面非常灵活,因此一个简单的解决方案仍能提供合理的结果,而不必采用拒绝逻辑,这是一个triangular distribution。即你将三角形的下端设置为1,000,三角形的上端设置为20,000,三角形的尖端设置为你想要的平均值为9,000。

上面的维基百科链接表明三角形分布的平均值为:

(a + b + c) / 3

其中ab分别是您的下限和上限,c是三角形的一角。对于您的输入,简单代数表示c = 6,000将给出您想要的平均值9,000。

在C ++的<random>标题中有一个名为std::piecewise_linear_distribution的分布,非常适合设置三角分布。这只需要两条直线。构建这种三角形分布的一种简单方法是:

std::piecewise_linear_distribution<> dist({1000., 6000., 20000.},
                                          [](double x)
                                          {
                                              return x == 6000 ? 1. : 0.;
                                          });

现在您只需将URNG插入此分发中并生成结果即可。为了理智,根据您的问题陈述收集一些重要的统计信息也很有帮助,例如最小值,最大值和平均值。

这是一个完整的程序:

#include <algorithm>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>

int
main()
{
    std::mt19937_64 eng;
    std::piecewise_linear_distribution<> dist({1000., 6000., 20000.},
                                              [](double x)
                                              {
                                                  return x == 6000 ? 1. : 0.;
                                              });
    std::vector<double> results;
    for (int i = 0; i < 100; ++i)
        results.push_back(dist(eng));
    auto avg = std::accumulate(results.begin(), results.end(), 0.) / results.size();
    auto minmax = std::minmax_element(results.begin(), results.end());
    std::cout << "size = " << results.size() << '\n';
    std::cout << "min = " << *minmax.first << '\n';
    std::cout << "avg = " << avg << '\n';
    std::cout << "max = " << *minmax.second << '\n';
}

可移植输出:

size = 100
min = 2353.05
avg = 8972.1
max = 18162.5

如果您将采样值的数量调高到足够高,您将看到参数收敛:

size = 10000000
min = 1003.08
avg = 8998.91
max = 19995.5

根据需要播种。

答案 2 :(得分:1)

以下是如何使用正态分布执行此操作,使用样本丢弃技术将值保持在边界内。这当然会扭曲分布,因此不再正常。这个效果有多大取决于您对标准偏差的原始选择。对您而言重要的程度取决于您的申请。

#include <iostream>
#include <random>

double get_random_number_with_minimum_mean_and_maximum(
    double minimum,
    double mean,
    double maximum
) {

    // Any uniform random generator of your choice could be used here.
    // Obviously making this static is not rentrant or thread-safe.
    static std::mt19937 generator;

    // We'll start with a normal distribution with a standard deviation set
    // such that ~99.7% of the time we'll get a number within the average width
    // of your upper and lower bounds.
    //
    // Why ~99.7% and not some other number? Because that corresponds to three
    // standard deviations, and you didn't specify any requirements, so I'm
    // just making assumptions on your behalf.
    double const average_bound_width = ((mean-minimum) + (maximum-mean)) / 2;
    double const standard_deviation  = average_bound_width / 3;
    std::normal_distribution<double> distribution(mean, standard_deviation);

    // Now, keep fetching numbers until we find one that is within our desired
    // bounds. Throwing numbers away randomly from a normal distribution does
    // not affect the mean, but since our bounds are going to be skewed, our
    // mean will probably get skewed slightly, but this will likely not be
    // very noticable.
    double value;
    do {
        value = distribution(generator);
    } while (value < minimum || maximum < value);

    return value;
}

int main() {
    for (int i=0; i<100; ++i) {
        std::cout << get_random_number_with_minimum_mean_and_maximum(
            1000,
            9000,
            20000
        ) << '\n';
    }
}

当我运行它时,我得到了这个输出:

9426.01
10458.7
9518.42
9945.55
9032.35
7268.34
11092.2
13705.6
6374.58
7290.7
7008.3
10075.4
15678
8089.93
5645.39
13607.6
11930.2
13799.4
12194.7
10390
8594.2
14625.4
10487.9
11116.9
9473.06
13868
12414.5
12711.2
9431.92
3570.35
3490.47
3974.69
6695.1
8642.8
10034.3
8757.84
10232.6
10441.1
18234.9
9862.67
2365.8
9982.83
10282
13492.3
11932.6
9399.23
7196.37
11793.8
9646.56
1232.16
7796.91
13297.7
13191.4
8340.9
9891.94
7998.53
8139.9
8813.12
8829.3
9408.99
7771.22
6957.75
6149.01
7139.31
1482.41
5893.11
12720.9
6009.68
12360.5
5557.36
3080.25
8922.16
7636.47
12109.1
11153.5
5434.98
8874.9
8599.4
7833.87
8525.87
7630.14
8595.15
9786.19
12644.8
6310.17
12696.1
8717.86
7199.22
7404.67
7410.03
6041.42
7930.46
6505.42
7772.88
4929.65
4686.06
7743.93
5211.43
12023.2
10380.5

平均值为~8980,仅100个样本非常接近9000。

如果我用100万个样本运行,平均值是~9049。

答案 3 :(得分:0)

这是一个连续的"power-shifted" distribution,可以返回范围内的任何值,并一次执行。平均值是所希望的,但模式通常在最接近平均值的两端。

double shiftable_distribution(double minimum, double mean, double maximum)
{
    double range = maximum - minimum;
    double scaledmean = (mean - minimum) / range;
    return pow((double)rand() / RAND_MAX, 
               (1.0 - scaledmean) / scaledmean) 
                * range + minimum;
}

分布实际上是什么样的(1000,9000,20000)

enter image description here

答案 4 :(得分:0)

执行此操作的一种方法:如果均匀生成范围为[l,x]的随机值的0≤a≤1,并且生成的 1-a [x,h]范围内的随机值均匀,平均值为:

m =((l + x)/ 2)* a +((x + h)/ 2)*(1-a)

因此,如果您想要特定的 m ,则可以使用 a x

例如,您可以设置 x = m ,因此 a =(h-m)/(h-l)