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

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

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

def get_loot(rolls):
    drops = 0

    for i in range(rolls):
        # getting a random float with 2 decimal places
        roll = random.randint(0, 10000) / 100
        if roll < 0.04:
            drops += 1

    return drops

for i in range(0, 10):
    print(get_loot(1000000))

python输出:

371
396
392
406
384
392
380
411
393
434

C++版本:

int get_drops(int rolls){
    int drops = 0;
    for(int i = 0; i < rolls; i++){
        // getting a random float with 2 decimal places
        float roll = (rand() % 10000)/100.0f;
        if (roll < 0.04){
            drops++;
        }
    }
    return drops;
}

int main()
{
    srand(time(NULL));
    for (int i = 0; i <= 10; i++){
        cout << get_drops(1000000) << "\n";
    }
}

C++输出:

602
626
579
589
567
620
603
608
594
610
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 :


# include <iostream>

# include <random>

# include <chrono>

int get_drops(int rolls) {
    std::mt19937 e{
            static_cast<unsigned int> (
                    std::chrono::steady_clock::now().time_since_epoch().count()
            )
    };
    std::uniform_int_distribution<int> d{0, 9999};
    int drops = 0;
    for (int i = 0; i < rolls; i++) {
        float roll = d(e) / 100.0f;
        if (roll < 0.04) {
            drops++;
        }
    }
    return drops;
}

int main() {
    for (int i = 0; i <= 10; i++) {
        std::cout << get_drops(1000000) << "\n";
    }
}

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

int get_drops(int rolls) {
    int drops = 0;
    for (int i = 0; i < rolls; i++) {
        float roll = (10000 * rand() / RAND_MAX) / 100.0f;
        if (roll < 0.04) {
            drops++;
        }
    }
    return drops;
}

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

laik7k3q

laik7k3q2#

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


# include <iostream>

# include <random>

int get_drops(int rolls)
{
    std::random_device rd;
    std::mt19937 gen{ rd() };
    std::uniform_real_distribution<> dis{ 0.0, 100.0 };
    int drops{ 0 };
    for(int roll{ 0 }; roll < rolls; ++roll)
    {
        if (dis(gen) < 0.04)
        {
            ++drops;
        }
    }

    return drops;
}

int main()
{
    for (int i{ 0 }; i <= 10; ++i)
    {
        std::cout << get_drops(1000000) << '\n';
    }
}
g9icjywg

g9icjywg3#

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

SEED = 101
TOP = 999
class my_random(object):
    def seed(self, a=SEED):
        """Seeds a deterministic value that should behave the same irrespectively of the coding language"""
        self.seedval = a
    def random(self):
        """generates and returns the random number based on the seed"""
        self.seedval = (self.seedval * SEED) % TOP
        return self.seedval

instance = my_random(SEED)
read_seed = instance.seed
read_random = instance.random()

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

const int SEED = 101;
const int TOP = 9999;
class myRandom(){
    int seedval;
    public int random();
    myRandom(int a=SEED){
        this.seedval = a;
    }
    int random(){
        this.seedval = (this.seedval * SEED) % TOP;
        return this.seedval;
    }
    int seed(){
        return this.seedval;
    }
}
instance = myRandom(SEED);
readSeed = instance.seed;
readRandom = instance.random();

相关问题