我如何根据用户输入生成 "weighted" 随机数,使某些数字优先于其他数字?

How can I do "weighted" random number generation that favors some numbers over others, depending on user input?

首先,我相信这也是基于数学的,所以模组,如果这不是解决此类问题的正确位置,请随时将其迁移到适当的位置。我在这里问,因为我希望这个问题在编程中实现,特别是在 c++ 中。

假设以下场景: - 我想 RNG 一个介于 0 和 8 之间的数字 - 有一个额外的输入考虑到正在生成的数字,以这种方式为某些数字提供更好的赔率(我会尽量清楚):

如果用户输入'0',生成的数字将有以下机会出现:

'0' - weight of 5,
'1' - weight of 4,
'2' - weight of 3,
'3' - weight of 2,
'4' - weight of 1,
'5' - weight of 0,
'6' - weight of 0,
'7' - weight of 0,
'8' - weight of 0,

因此,获得随机“0”的机会是获得“4”的 5 倍,而获得“5”、“6”、“7”和“8”的机会为零。

如果用户输入'4',则权重如下:

'0' - weight of 1,
'1' - weight of 2,
'2' - weight of 3,
'3' - weight of 4,
'4' - weight of 5,
'5' - weight of 4,
'6' - weight of 3,
'7' - weight of 2,
'8' - weight of 1

在这种情况下,所有数字都有机会出现,但有利于生成数字'4'。 此外,数字“3”和“5”有相同的机会出现,但比数字“4”的可能性要小。

以此类推

这可以转化为权重table如下图所示:

Table of Weights image

考虑到我已经把问题说清楚了(如果没有,请告诉我!我会尽量用更好的方式解释),请问如何设计解决这个问题的方案?

我标记 c++ 是因为这是我正在学习的语言,但这通常可以应用于任何语言。

此致!

看起来你想要std::discrete_distribution:

std::discrete_distribution produces random integers on the interval [0, n), where the probability of each individual integer i is defined as w_i = i/S, that is the weight of the ith integer divided by the sum of all n weights. [cppreference.com]

如果你的table是std::vector<unsigned int> weights,你可以写

std::random_device rd;
std::mt19937 gen(rd());
std::discrete_distribution<> d(weights.begin(), weights.end());

然后用d(gen)得到随机数。

如果 weights 数组在 compile-time 处具有已知的静态大小,您可以使用完全相同的语法使用 std::array

我的方法是

根据用户输入添加所有权重,在第一个示例中为 5+4+3+2+1+0+0+0(总和=15),1+2+3+4+5+ 4+3+2+1 (sum=25) 在第 2.

在区间[0,sum-1]中选择一个随机整数

根据您的table映射,例如0-4 => 0、5-8 => 1 等等

按照@Evg

的建议使用std::discrete_distribution<>

我做的这个示例代码完全符合我的要求!

否 random_device 因为我正在 Android 编码...

#include <iostream>
#include <vector>
#include <chrono>
#include <random>

int main()
{
    std::vector<int> v {};
    std::cout << "Input vector size:\n";
    size_t vSize {0};
    std::cin >> vSize;
    v.resize(vSize);
    std::cout << "input max weight:\n";
    int maxWeight {0};
    std::cin >> maxWeight;
    std::cout << "Input the vector position for max weight:\n";
    int pos {0};
    std::cin >> pos;
    std::cout << "filling vector with weights...\n";
    for (int i {pos - 1}, j {0}; i < static_cast<int>(v.size()); ++i, ++j)
    {
        v[static_cast<size_t>(i)] = maxWeight - j > 0 ? maxWeight - j : 0;
    }
    for (int i {pos - 1}, j {0}; i >= 0; --i, ++j)
    {
        v[static_cast<size_t>(i)] = maxWeight - j > 0 ? maxWeight - j : 0;
    }
    std::cout << "Done.\n\nPrinting the array weight map:\n";
    for (int element : v)
    {
        std::cout << element << '\n';
    }
    using chrono_t = std::chrono::high_resolution_clock;
    const auto seed {chrono_t::now().time_since_epoch().count()};
    std::mt19937 mt {static_cast<unsigned long int>(seed)};
    std::discrete_distribution<> rng(v.begin(), v.end());
    std::cout << "- - - Generating 1 000 000 numbers: - - -\n";
    std::vector<int> numCount {};
    numCount.resize(vSize, 0);
    for (int i {0}; i < 1000000; ++i)
    {
        ++numCount[static_cast<size_t>(rng(mt))];
    }
    {//scope
        int i {0};
        for (auto element : numCount)
        {
            std::cout << "Number of '" << i << "'s: " << element << '\n';
            ++i;
        }
    }//scope
    std::cout << '\n';
    return 0;
}

这是一个示例 运行,它与我在问题中添加的 table 匹配:

Input vector size:
9
input max weight:
5
Input the vector position for max weight:
5
filling vector with weights...
Done. 
Printing the array weight map:
1
2
3
4
5
4
3
2
1
- - - Generating 1 000 000 numbers: - - -
Number of '0's: 40032
Number of '1's: 79854
Number of '2's: 120201
Number of '3's: 160531
Number of '4's: 200083
Number of '5's: 159642
Number of '6's: 119873
Number of '7's: 80057
Number of '8's: 39727

确实很简单,但是当你刚开始学习的时候,事情可能看起来比实际情况要复杂。

此致!