【问题标题】:Random Dice not reseeding随机骰子不重新播种
【发布时间】:2012-09-05 21:46:01
【问题描述】:

我创建了以下函数来为骰子游戏创建随机数

#include <iostream>
#include <ctime>
#include <cstdlib>
#include "dice.h"
#include "display.h"
using namespace std;
int die[6][10];
void dice(int times, int dice){
    int r;
    for(int x=0;x<times;x++){
        for(int x=0;x<dice;x++){
            srand(time(0));
            r=(rand() % 5);
            die[r][x]+=1;
            cout<<"Die #"<<x+1<<" rolled a "<<r<<endl;
        }
    }

}

但它不会重新播种。它只是为每个骰子输出相同的数字。有谁知道我该如何解决?

【问题讨论】:

  • 还要注意,rand() % 5 周围不需要括号。此外,该表达式产生从 to 到 4 的值,因此 die[5] 永远不会受到打击。为避免此类错误,请使用常量来定义面数(而不是硬编码 6 和 5),并在数组定义中使用该常量并作为除数。

标签: c++ random srand


【解决方案1】:

您没有正确使用 srand 和 rand 函数。您应该“播种”一次随机数生成器,然后使用rand() 从 RNG 中检索连续值。每个种子产生符合特定随机标准的特定数字序列。

相反,您每次都为随机数生成器播种,然后检索随机序列中的第一个值。由于time() 被调用得如此之快以至于它返回相同的种子,因此您实际上将随机数生成器重置为相同序列的开头,因此您得到的数字与之前相同。

即使time() 返回的值更新得足够快,以至于您每次都获得一个新种子,但仍不能保证您获得良好的随机数。随机数生成器旨在生成一个数字序列,其中该序列具有某些统计属性。但是,不能保证相同的属性适用于从 不同 序列中选择的值。

因此,要使用确定性随机数生成器,您应该只为生成器播种一次,然后使用该种子生成的值序列。


另外一点;用于实现rand() 的随机数生成器在历史上并不是很好,rand() 不是可重入的或线程安全的,并且将rand() 生成的值转换为具有所需分布的值并不总是那么简单。

在 C++ 中,您应该更喜欢 &lt;random&gt; 库,它提供了更好的功能。这是一个使用&lt;random&gt;的例子。

#include <random>
#include <iostream>

int main() {
    const int sides = 6;
    int groups = 10, dice_per_group = 3;

    std::uniform_int_distribution<> distribution(1,sides); // create an object that uses randomness from an external source (provided later) to produces random values in the given (inclusive) range

    // create and seed the source of randomness
    std::random_device r;
    std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
    std::mt19937 engine(seed);

    for (int i=0; i<groups; ++i) {
        for (int j=0; j<dice_per_group; ++j) {
            // use the distribution with the source of randomness
            int r = distribution(engine);
            std::cout << "Die #" << j+1 << " rolled a " << r << '\n';
        }
        std::cout << '\n';
    }
}

【讨论】:

    【解决方案2】:

    srand() 在函数中被重复调用,或者循环不好。

    在 main 中调用 srand()。每个程序只调用一次。

    【讨论】:

    • 这个答案显然解决了问题,但没有很好地描述导致问题的原因。问题是 time() 返回相同的值,因为它被调用得太快以至于没有足够的时间让它产生下一个时间值。如果调用之间的时间更长,则用于播种 RNG 的值以及来自rand() 的结果值看起来会更加随机。
    • 虽然这不会真正使用 RNG 生成随机数字序列,但您只是从每个序列中获取第一个值。这不一定具有与播种 RNG 一次然后多次调用 rand() 以检索 RNG 生成的连续值相同的统计属性。
    • 我真的很懒得解释。对此我深表歉意。这么说有点过分了。实际上,在某些情况下,您可能希望在具有某些已知种子或传递变量种子的函数中使用 srand。唯一想到的...假设您制作了一个随机生成关卡的游戏。您可以允许用户将种子提供给 srand,如果没有提供,则使用时间之类的东西,或者在 Linux 机器上使用 /dev/urandom。有许多比 time() 更好的播种 srand 的方法,但是你放弃了可移植性。
    【解决方案3】:

    您只想为正在执行的任何模拟调用一次 srand()。这样做的原因是每次调用都会重新设置 rand() 的种子,这会对 rand() 值施加偏差。如果您假设 i.i.d.,这一点尤其重要

    在上述情况下,您希望将 srand() 移出循环。

    【讨论】:

      【解决方案4】:

      您只想调用 srand() 一次。时间太短了, time() 返回相同的值。所以随机数生成器从同一个地方开始。

      如果可能,在函数之前调用 srand,或者在函数的开头。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-07
        • 1970-01-01
        • 2018-03-29
        • 2011-07-18
        • 2016-05-04
        • 2013-12-18
        • 1970-01-01
        相关资源
        最近更新 更多