随机数生成器,C++

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5019393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:11:41  来源:igfitidea点击:

Random number generator, C++

c++random

提问by notrockstar

I know there is a bit of limitations for a random number generation in C++ (can be non-uniform). How can I generate a number from 1 to 14620?

我知道 C++ 中的随机数生成有一些限制(可能是不统一的)。如何生成从 1 到 14620 的数字?

Thank you.

谢谢你。

回答by wilhelmtell

A common approach is to use std::rand()with a modulo:

一种常见的方法是使用std::rand()模数:

#include<cstdlib>
#include<ctime>

// ...
std::srand(std::time(0));  // needed once per program run
int r = std::rand() % 14620 + 1;

However, as @tenfour mentions in his answer, the modulo operator can disrupt the uniformity of values std::rand()returns. This is because the modulo translates the values it discards into valid values, and this translation might not be uniform. For instance, for nin [0, 10)the value n % 9translates 9to 0, so you can get zero by either a true zero or a 9 translated to zero. The other values have each only one chance to yield.

然而,正如@tenfour 在他的回答中提到的,模运算符会破坏值std::rand()返回的一致性。这是因为模将它丢弃的值转换为有效值,并且这种转换可能不统一。例如, forn[0, 10)n % 9转换90,因此您可以通过真正的零或转换为零的 9 来获得零。其他值都只有一次屈服的机会。

An alternative approach is to translate the random number from std::rand()to a floating-point value in the range [0, 1)and then translate and shift the value to within the range you desire.

另一种方法是将随机数从std::rand()范围内[0, 1)转换为浮点值,然后将值转换并移动到您想要的范围内。

int r = static_cast<double>(std::rand()) / RAND_MAX * 14620) + 1;

回答by Howard Hinnant

If you've got a c++0x environment, a close derivative of the boost lib is now standard:

如果你有一个 c++0x 环境,boost 库的一个近似派生现在是标准的:

#include <random>
#include <iostream>

int main()
{
    std::uniform_int_distribution<> d(1, 14620);
    std::mt19937 gen;
    std::cout << d(gen) << '\n';
}

This will be fast, easy and high quality.

这将是快速、简单和高质量的。

You didn't specify, but if you wanted floating point instead just sub in:

您没有指定,但如果您想要浮点数,则只需输入:

std::uniform_real_distribution<> d(1, 14620);

And if you needed a non-uniform distribution, you can build your own piece-wise constant or piece-wise linear distribution very easily.

如果您需要非均匀分布,您可以非常轻松地构建自己的分段常数或分段线性分布。

回答by tenfour

srand() / rand()are the functions you need, as others have answered.

srand() / rand()是您需要的功能,正如其他人所回答的那样。

The problem with %is that the result is decidedly non-uniform. To illustrate, imagine that rand()returns a range of 0-3. Here are hypothetical results of calling it 4000 times:

问题%在于结果显然是不均匀的。为了说明,假设rand()返回 0-3 的范围。以下是调用它 4000 次的假设结果:

0 - 1000 times
1 - 1000 times
2 - 1000 times
3 - 1000 times

Now if you do the same sampling for (rand() % 3), you notice that the results would be like:

现在,如果您对 进行相同的采样(rand() % 3),您会注意到结果如下:

0 - 2000 times
1 - 1000 times
2 - 1000 times

Ouch! The more uniform solution is this:

哎哟! 更统一的解决方案是这样的:

int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);

int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);

Sorry for the sloppy code, but the idea is to scale it down properly to the range you want using floating point math, and convert to integer.

对于草率的代码很抱歉,但我们的想法是使用浮点数学将其正确缩小到您想要的范围,然后转换为整数。

回答by James

Use rand.

使用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

EDIT:

编辑:

As mentioned in the link, the randomizer should be seeded using srandbefore use. A common distinctive value to use is the result of a call to time.

如链接中所述,随机发生器应在使用srand前进行播种。要使用的常见独特值是调用 的结果time

回答by Malte

As already said, you can use rand(). E.g.

如前所述,您可以使用rand()。例如

int n = rand() % 14620 + 1;

int n = rand() % 14620 + 1;

does the job, but it is non-uniform. That means some values (low values) will occur slightly more frequently. This is because rand()yields values in the range of 0 to RAND_MAXand RAND_MAXis generally not divisible by 14620. E.g. if RAND_MAX == 15000, then the number 1 would be twice as likely as the number 1000 because rand() == 0and rand() == 14620both yield n==1but only rand()==999makes n==1000true.

完成这项工作,但它是不均匀的。这意味着某些值(低值)会更频繁地出现。这是因为rand()产生的值在 0 到14620的范围内,RAND_MAX并且RAND_MAX通常不能被 14620 整除。例如,如果RAND_MAX == 15000,那么数字 1 的可能性是数字 1000 的两倍,因为rand() == 0rand() == 14620两者都产生n==1但只rand()==999使n==1000真。

However, if 14620 is much smaller than RAND_MAX, this effect is negligible. On my computer RAND_MAXis equal to 2147483647. If rand()yields uniform samples between 0 and RAND_MAX then, because 2147483647 % 14620 = 10327 and 2147483647 / 14620 = 146886, nwould be between 1 and 10328 on average 146887 times while the numbers between 10329 and 14620 would occur on average 146886 times if you draw 2147483647 samples. Not much of a difference if you ask me.

但是,如果 14620 远小于RAND_MAX,则这种影响可以忽略不计。在我的电脑RAND_MAX上等于 2147483647。如果rand()在 0 和 RAND_MAX 之间产生均匀的样本,那么因为 2147483647 % 14620 = 10327 和 2147483647 / 14620 = 146886,n将在 28 次和 103 次 103 次 103 次 103 次 103 次 103 次 18 次之间的 28 次平均出现如果您抽取 2147483647 个样本,则平均为 146886 次。如果你问我,差别不大。

However, if RAND_MAX == 15000it would make a difference as explained above. In this case some earlier posts suggested to use

但是,如果RAND_MAX == 15000它会产生如上所述的不同。在这种情况下,建议使用一些较早的帖子

int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);

int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);

to make it 'more uniform'. Note that this only changes the numbers that occur more frequently since rand()still returns 'only' RAND_MAXdistinct values. To make it really uniform, you would have to reject any integer form rand()if it is in the range between 14620*int(RAND_MAX/14620) and RAND_MAX and call rand()again. In the example with RAND_MAX == 15000you would reject any values of rand()between 14620 and 15000 and draw again. For most application this is not necessary. I would worry more about the randomness of rand().

使其“更统一”。请注意,这只会更改更频繁出现的数字,因为它rand()仍然返回“仅”RAND_MAX不同的值。为了使它真正统一,rand()如果它在 14620*int(RAND_MAX/14620) 和 RAND_MAX 之间的范围内,则必须拒绝任何整数形式,然后rand()再次调用。在示例中,RAND_MAX == 15000您将拒绝rand()14620 和 15000 之间的任何值并再次绘制。对于大多数应用程序,这不是必需的。我会更担心rand().

回答by Lima X

The rand() function is not really the best Random generator, a better way would be by using CryptGenRandom().

rand() 函数并不是最好的随机生成器,更好的方法是使用 CryptGenRandom()。

This example should do do the trick:

这个例子应该可以解决问题:

#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;
}

回答by user2808359

the modulus operator is the most important, you can apply a limit with this modulus, check this out:

模数运算符是最重要的,您可以使用此模数应用限制,请查看:

// 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