我如何根据用户输入生成 "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如下图所示:
考虑到我已经把问题说清楚了(如果没有,请告诉我!我会尽量用更好的方式解释),请问如何设计解决这个问题的方案?
我标记 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 i
th 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
确实很简单,但是当你刚开始学习的时候,事情可能看起来比实际情况要复杂。
此致!
首先,我相信这也是基于数学的,所以模组,如果这不是解决此类问题的正确位置,请随时将其迁移到适当的位置。我在这里问,因为我希望这个问题在编程中实现,特别是在 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如下图所示:
考虑到我已经把问题说清楚了(如果没有,请告诉我!我会尽量用更好的方式解释),请问如何设计解决这个问题的方案?
我标记 c++ 是因为这是我正在学习的语言,但这通常可以应用于任何语言。
此致!
看起来你想要std::discrete_distribution
:
std::discrete_distribution
produces random integers on the interval[0, n)
, where the probability of each individual integeri
is defined asw_i = i/S
, that is the weight of thei
th integer divided by the sum of alln
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
确实很简单,但是当你刚开始学习的时候,事情可能看起来比实际情况要复杂。
此致!