在Python和C++中生成相似的随机数,但得到不同的输出

2wnc66cl  于 2021-08-20  发布在  Java
关注(0)|答案(3)|浏览(488)

在C++和Python中,我有两个函数,它决定在某个卷上发生某个概率的事件的次数。
python版本:

  1. def get_loot(rolls):
  2. drops = 0
  3. for i in range(rolls):
  4. # getting a random float with 2 decimal places
  5. roll = random.randint(0, 10000) / 100
  6. if roll < 0.04:
  7. drops += 1
  8. return drops
  9. for i in range(0, 10):
  10. print(get_loot(1000000))

python输出:

  1. 371
  2. 396
  3. 392
  4. 406
  5. 384
  6. 392
  7. 380
  8. 411
  9. 393
  10. 434

C++版本:

  1. int get_drops(int rolls){
  2. int drops = 0;
  3. for(int i = 0; i < rolls; i++){
  4. // getting a random float with 2 decimal places
  5. float roll = (rand() % 10000)/100.0f;
  6. if (roll < 0.04){
  7. drops++;
  8. }
  9. }
  10. return drops;
  11. }
  12. int main()
  13. {
  14. srand(time(NULL));
  15. for (int i = 0; i <= 10; i++){
  16. cout << get_drops(1000000) << "\n";
  17. }
  18. }

C++输出:

  1. 602
  2. 626
  3. 579
  4. 589
  5. 567
  6. 620
  7. 603
  8. 608
  9. 594
  10. 610
  11. 626

这只乌鸦看起来一模一样(至少在我看来)。这两个函数都模拟1000000次转鼓的概率为0.04的事件发生。然而,Python版本的输出比C++版本低30%左右。这两个版本有何不同?为什么它们有不同的输出?

evrscar2

evrscar21#

在C++(0)和RANDMAX之间的范围内返回一个伪随机整数。 RAND_MAX 是“依赖于库,但保证在任何标准库实现上至少为32767。”
我们开始吧 RAND_MAX 32767。
当计算[0,32767)%10000时,随机数生成是倾斜的。
值0-2767在范围(%10000)->
值计算结果11%10000110001%100001000120001%10000130001%10000130001%100001
其中,值2768-9999在范围(%10000)内仅出现3次->
值计算结果27682768%10000276812768%10000276882276822768%1000027768
这使得值0-2767比值2768-9999(假设)更可能出现25% rand() 事实上,会在0和rand_max)之间产生一个均匀分布。
另一方面,python使用randint在开始和结束之间生成一个均匀的分布 randint 是“randrange(a,b+1)的别名”
randrange(在python 3.2及更新版本中)将生成均匀分布的值:
在版本3.2中进行了更改:randrange()在生成均匀分布的值方面更加复杂。以前它使用int(random()*n)这样的样式,这可能会产生稍微不均匀的分布。
在C++中有几种生成随机数的方法。也许最类似于 python 将使用mersenne twister引擎(与python相同,但有一些不同)。
通过 uniform_int_distribution 具有 mt19937 :

  1. # include <iostream>
  2. # include <random>
  3. # include <chrono>
  4. int get_drops(int rolls) {
  5. std::mt19937 e{
  6. static_cast<unsigned int> (
  7. std::chrono::steady_clock::now().time_since_epoch().count()
  8. )
  9. };
  10. std::uniform_int_distribution<int> d{0, 9999};
  11. int drops = 0;
  12. for (int i = 0; i < rolls; i++) {
  13. float roll = d(e) / 100.0f;
  14. if (roll < 0.04) {
  15. drops++;
  16. }
  17. }
  18. return drops;
  19. }
  20. int main() {
  21. for (int i = 0; i <= 10; i++) {
  22. std::cout << get_drops(1000000) << "\n";
  23. }
  24. }

值得注意的是,这两个引擎的底层实现以及种子和分发都略有不同,但是,这将更接近python。
或者,正如matthias fripp所建议的那样,按比例放大兰德并除以 RAND_MAX :

  1. int get_drops(int rolls) {
  2. int drops = 0;
  3. for (int i = 0; i < rolls; i++) {
  4. float roll = (10000 * rand() / RAND_MAX) / 100.0f;
  5. if (roll < 0.04) {
  6. drops++;
  7. }
  8. }
  9. return drops;
  10. }

这也更接近python输出(同样,在底层实现中生成随机数的方式上存在一些差异)。

展开查看全部
laik7k3q

laik7k3q2#

结果是倾斜的,因为 rand() % 10000 这不是实现均匀分布的正确方法(另见stephan t.认为有害的rand()。在现代C++中,首选头文件中提供的伪随机数生成库。 <random> . 例如:

  1. # include <iostream>
  2. # include <random>
  3. int get_drops(int rolls)
  4. {
  5. std::random_device rd;
  6. std::mt19937 gen{ rd() };
  7. std::uniform_real_distribution<> dis{ 0.0, 100.0 };
  8. int drops{ 0 };
  9. for(int roll{ 0 }; roll < rolls; ++roll)
  10. {
  11. if (dis(gen) < 0.04)
  12. {
  13. ++drops;
  14. }
  15. }
  16. return drops;
  17. }
  18. int main()
  19. {
  20. for (int i{ 0 }; i <= 10; ++i)
  21. {
  22. std::cout << get_drops(1000000) << '\n';
  23. }
  24. }
展开查看全部
g9icjywg

g9icjywg3#

两种语言都使用不同的伪随机生成器。如果要统一性能,可能需要确定地生成自己的伪随机值。
以下是它在python中的外观:

  1. SEED = 101
  2. TOP = 999
  3. class my_random(object):
  4. def seed(self, a=SEED):
  5. """Seeds a deterministic value that should behave the same irrespectively of the coding language"""
  6. self.seedval = a
  7. def random(self):
  8. """generates and returns the random number based on the seed"""
  9. self.seedval = (self.seedval * SEED) % TOP
  10. return self.seedval
  11. instance = my_random(SEED)
  12. read_seed = instance.seed
  13. read_random = instance.random()

然而,在C++中,应该成为:

  1. const int SEED = 101;
  2. const int TOP = 9999;
  3. class myRandom(){
  4. int seedval;
  5. public int random();
  6. myRandom(int a=SEED){
  7. this.seedval = a;
  8. }
  9. int random(){
  10. this.seedval = (this.seedval * SEED) % TOP;
  11. return this.seedval;
  12. }
  13. int seed(){
  14. return this.seedval;
  15. }
  16. }
  17. instance = myRandom(SEED);
  18. readSeed = instance.seed;
  19. readRandom = instance.random();
展开查看全部

相关问题