[英]Random number generator, C++
我知道 C++ 中的随机数生成有一些限制(可能是不统一的)。 如何生成从 1 到 14620 的数字?
谢谢你。
如果你有一个 c++0x 环境,boost 库的一个近似派生现在是标准的:
#include <random>
#include <iostream>
int main()
{
std::uniform_int_distribution<> d(1, 14620);
std::mt19937 gen;
std::cout << d(gen) << '\n';
}
这将是快速、简单和高质量的。
您没有指定,但如果您想要浮点数,则只需输入:
std::uniform_real_distribution<> d(1, 14620);
如果您需要非均匀分布,您可以非常轻松地构建自己的分段常数或分段线性分布。
一种常见的方法是将std::rand()
与模数一起使用:
#include<cstdlib>
#include<ctime>
// ...
std::srand(std::time(0)); // needed once per program run
int r = std::rand() % 14620 + 1;
然而,正如@tenfour 在他的回答中提到的,模运算符会破坏std::rand()
返回值的一致性。 这是因为模将它丢弃的值转换为有效值,并且这种转换可能不统一。 例如,对于n
在[0, 10)
的值n % 9
转化9
至0
,这样你就可以通过一个真正的零或9翻译成零获得零。 其他值都只有一次屈服的机会。
另一种方法是将随机数从std::rand()
转换为[0, 1)
范围内的浮点值,然后将值转换并移动到您想要的范围内。
int r = static_cast<double>(std::rand()) / RAND_MAX * 14620) + 1;
srand() / rand()
是您需要的功能,正如其他人所回答的那样。
%
的问题在于结果显然是不均匀的。 为了说明这一点,假设rand()
返回 0-3 的范围。 以下是调用它 4000 次的假设结果:
0 - 1000 times
1 - 1000 times
2 - 1000 times
3 - 1000 times
现在,如果您对(rand() % 3)
进行相同的采样,您会注意到结果如下:
0 - 2000 times
1 - 1000 times
2 - 1000 times
哎哟! 更统一的解决方案是这样的:
int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);
对于草率的代码很抱歉,但我们的想法是使用浮点数学将其正确缩小到您想要的范围,然后转换为整数。
使用rand 。
( rand() % 100 ) is in the range 0 to 99
( rand() % 100 + 1 ) is in the range 1 to 100
( rand() % 30 + 1985 ) is in the range 1985 to 2014
( rand() % 14620 + 1 ) is in the range 1 to 14620
编辑:
如链接中所述,随机srand
应在使用前使用srand
进行播种。 一个常用的独特值是调用time
的结果。
如前所述,您可以使用rand() 。 例如
int n = rand() % 14620 + 1;
完成这项工作,但它是不均匀的。 这意味着某些值(低值)会更频繁地出现。 这是因为rand()
产生 0 到RAND_MAX
范围内的值,并且RAND_MAX
通常不能被 14620 整除。例如,如果RAND_MAX == 15000
,那么数字 1 的可能性是数字 1000 的两倍,因为rand() == 0
和rand() == 14620
都产生n==1
但只有rand()==999
使n==1000
真。
但是,如果 14620 远小于RAND_MAX
,则这种影响可以忽略不计。 在我的计算机上RAND_MAX
等于 2147483647。如果rand()
产生介于 0 和 RAND_MAX 之间的均匀样本,那么,因为 2147483647 % 14620 = 10327 和 2147483647 / 14620 = 14688816 和n
之间的 14688816 和n
之间的平均数为 1836,如果您抽取 2147483647 个样本,则 10329 和 14620 将平均出现 146886 次。 如果你问我,差别不大。
但是,如果RAND_MAX == 15000
,则会产生如上所述的不同。 在这种情况下,建议使用一些较早的帖子
int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);
使其“更统一”。 请注意,这只会更改更频繁出现的数字,因为rand()
仍然返回“仅” RAND_MAX
不同值。 为了使其真正统一,您必须拒绝任何整数形式的rand()
如果它在 14620*int(RAND_MAX/14620) 和 RAND_MAX 之间的范围内,然后再次调用rand()
。 在RAND_MAX == 15000
的示例中,您将拒绝rand()
14620 和 15000 之间的任何值并再次绘制。 对于大多数应用程序,这不是必需的。 我会更担心rand()
的随机性。
rand() 函数并不是最好的随机生成器,更好的方法是使用 CryptGenRandom()。
这个例子应该可以解决问题:
#include <Windows.h>
// Random-Generator
HCRYPTPROV hProv;
INT Random() {
if (hProv == NULL) {
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT))
ExitProcess(EXIT_FAILURE);
}
int out;
CryptGenRandom(hProv, sizeof(out), (BYTE *)(&out));
return out & 0x7fffffff;
}
int main() {
int ri = Random() % 14620 + 1;
}
模数运算符是最重要的,您可以使用此模数应用限制,请查看:
// random numbers generation in C++ using builtin functions
#include <iostream>
using namespace std;
#include <iomanip>
using std::setw;
#include <cstdlib> // contains function prototype for rand
int main()
{
// loop 20 times
for ( int counter = 1; counter <= 20; counter++ ) {
// pick random number from 1 to 6 and output it
cout << setw( 10 ) << ( 1 + rand() % 6 );
// if counter divisible by 5, begin new line of output
if ( counter % 5 == 0 )
cout << endl;
}
return 0; // indicates successful termination
} // end main
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.