繁体   English   中英

随机数生成器,C++

[英]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转化90 ,这样你就可以通过一个真正的零或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() == 0rand() == 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM