我知道在C++中生成随机数有一些限制(可能是不均匀的)。那么如何生成1到14620之间的数字呢?
谢谢。
我知道在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);
如果你需要非均匀分布,你可以很容易地构建自己的分段常数分布或分段线性分布。
闭区间
[1,14620]内的数字,而uniform real分布返回半开区间
[1,14620)内的数字。 - Blastfurnacestd::random_device r; std::mt19937 gen(r());
。 - Cubbi常用的方法是使用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()
返回值的一致性。这是因为模运算会将它丢弃的值转换成有效值,并且这种转换可能不是一致的。例如,对于[0, 10)
中的n
,值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_MAX
,您可以生成介于 0.0 和 1.0 之间的均匀随机数。这使得它很容易缩放到您想要的任何范围。在您的情况下,是 1-14620。 - tenfour( 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
进行初始化。常用的区分值是调用time
函数的结果。
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
成立。RAND_MAX
,则此效果是可以忽略的。在我的电脑上,RAND_MAX
等于2147483647。如果rand()
在0到RAND_MAX之间产生均匀样本,则由于2147483647%14620 = 10327且2147483647 / 14620 = 146886,n
平均会在1到10328之间出现146887次,而在10329和14620之间的数字平均会出现146886次,如果您绘制了2147483647个样本。RAND_MAX == 15000
,它将会有所不同,如上所述。
在这种情况下,一些早期的帖子建议使用:
int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);
使其“更均匀”。
请注意,这仅更改更频繁出现的数字,因为rand()
仍然返回“仅”RAND_MAX
个不同的值。
要使其真正均匀,您必须拒绝任何在14620 * int(RAND_MAX / 14620)和RAND_MAX之间的整数形式rand()
并再次调用rand()
。
在RAND_MAX == 15000
的示例中,您将拒绝在14620和15000之间的任何rand()
值,并再次绘制。
对于大多数应用程序,这是不必要的。我会更担心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