【问题标题】:C++ Random number generator: How to make numbers random upon every executionC++ 随机数生成器:如何在每次执行时使数字随机化
【发布时间】:2015-08-15 10:43:59
【问题描述】:

我不认为这是重复的,因为我尝试了其他 SO 答案,但它们对我不起作用。当我运行一个程序(随时间播种)时,我得到一堆随机数。几秒钟后,我再次运行程序,得到了一堆类似的随机数。

srand(time(0));
for(int i=0; i<10; i++) {
    cout<<rand()<<"\n";
}

8603 55 3146 26251 14799 16799 28230 314 3602 9504

8639 19984 3044 28803 29955 27225 29699 882 21389 7411

如您所见,数字不同,但非常相似。这对我不起作用的原因是因为我将它转换为 0 和 1 之间的浮点数(除以 RAND_MAX)。当我这样做时,以秒为单位的时间非常缓慢。在一次运行中,我可以拥有 0.09245... ,接下来我可以拥有 0.0925... 。我正在使用这些概率来制作二十一点 AI,并且我不希望相同的投注模式出现在随后的执行中。

我看了很多遍,并试图将种子放入循环中,但只是打印了 10 次相同的数字。不知道如何使数字在执行时看起来完全随机。感谢您的想法

编辑:

使用

    srand(rd());    
    for(int i=0; i<10; i++) {   
        cout<<generate()<<"\n";
    }

14514284786278117030 4620546740167642908 13109570281517897720 1746293864714​​8434322 355488278567739596 7469126240319926998 4635995468481642529 418970542659199878 9604170989252516556 6358044926049913402

我认为每次运行时我都会得到完全相同的序列。

编辑 2:

一点背景知识以消除混乱。我希望分布均匀,但如果不是这样也没关系,这只是我自己的做法,没有赌场业务。我最初的计划是让 6 个字符有一个值为 12-20 的命中/停留概率数组。因此,就像吉姆一样,[0.958367, 0.942123, 0.876655, 0.864322, 0.7543321, 0.653213, 0.201201, 0.12919, 0.00001] 将这些数字组合起来。假设 Jim 有一手 14 点。所以我得到一个随机的 0-1 数字,如果它小于 0.876655,那么他会击中。 100轮后的优胜者将混合他们的“基因”,也许在1000轮后,自然会选出完美的孩子,并形成完美的命中/传球比。这就是我注意到 Pam 或其他人总是会击中的原因:他们的随机生成总是下降到 0.05 左右,所以无论她的手有多好或多坏,她都会击中。我几乎完成了,唯一的事情是修复这个随机生成器和另一个处理投注钱的小错误(我保证不相关)

【问题讨论】:

  • 对不起,意思是类似的。我的错,不想骗你会编辑
  • 代码没有问题,您看到的相似之处并不存在或只是巧合。
  • srand () 和 random () 在这一点上实际上是玩具,委员会甚至可能会弃用它们。 C++11 使用 std::uniform_*distribution 有更好的支持。见:stackoverflow.com/questions/19665818/…
  • 我建议你研究一下引擎和发行版。
  • 如果它们是随机的,谁在乎它们是什么?随机就是随机。如前所述,rand 不是最好的,并且使用除以最大值也是有偏差的,但结果仍然应该是用眼球测试“检测不到”的。随机就是随机。生成许多​​序列并绘制分布图以查看是否(以及在何种程度上)存在问题;不要依赖眼球联想来争论这种或另一种方式。

标签: c++ random


【解决方案1】:

如果可能,请使用std::random_device 获取您的种子,并使用std::mt19937_64 生成您的号码。 std::random_device 旨在(但不幸的是,不能保证)使用硬件来生成真正的随机数,因此至少在一个好的实现中,它确实是非常随机的(但带宽相当低)。

C++11 渲染的 rand 和 srand 几乎已经过时了。

这是一个相当演示的程序:

#include <random>
#include <iostream>

int main() { 

    std::mt19937_64 gen{ std::random_device()() };
    std::uniform_real_distribution<double> dis{ 0.0, 1.0 };

    for (int i=0; i<10; i++)
        std::cout << dis(gen) << "\n";
}

至少在库的实现相当不错的情况下,这应该会产生相当可靠的结果。

【讨论】:

  • 您好,非常感谢您的回答,非常有用!但是现在我使用它并运行了两次,它仍然具有彼此接近的球场数字(将编辑新数据)。此外,数字很大,您是否知道 mt19937_64 是否有 Max 函数?我希望他们能够在 0-1 之间。抱歉,如果我遗漏了一些非常明显的东西,我只是使用 rand 和 srand,因为这是他们在学校教给我们的,我对新趋势很慢。谢谢
  • 对于 0 到 1 之间的数字,您希望将其与 std::uniform_real_distribution 一起使用。
  • 其实我收回了。每次我在循环中运行它时,它都会产生完全相同的数字。
  • @ScriptKitty:你确定你的调用正确吗?请参阅更新的答案以获取快速演示。如果该演示程序在连续运行中给出相同的结果,那么您的实现一定是非常糟糕的(如果知道您使用的是什么,我将不胜感激)。
  • @ScriptKitty “在循环中播种”是 uhh .. 不要那样做。一个 [good] PRNG,比如 MT,负责更新自己的状态,不需要任何帮助。
【解决方案2】:

这里有一个例子,我认为你想要它做的事情:

//I'm guessing your time(0) was intended to be this?
static DWORD dwTime = timeGetTime();//static = value doesn't change
srand(dwTime);
while (1) //while the app is running, perform these actions.
{
    DWORD dwCurrTime = timeGetTime();
    for (int i = 0; i < 10; i++) {
        cout << rand() % 10 + 1 << "\n"; //1-10 
        //if dwTime + 500 milliseconds is less than current timeGetTime()
        //sleep, this allows you to check the code easily for repeats
        if (dwTime + 500 < dwCurrTime)
            Sleep(10000);
    }
}

【讨论】:

  • 这如何回答 OP 的问题?他们想知道为什么这些数字相似。
  • 问题是如何在每次执行后使数字随机化,我举了一个例子,在我的测试之后似乎是相当随机的,还有一些额外的代码应该让他们更容易比较数字。
  • 是时候让rand()离开了。 C++ 的随机数功能在 C++11 中得到了极大的扩展和增强,是时候开始使用它们了。 rand() 是一个非常糟糕的随机数生成器。另见:open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3924.pdf
  • 啊,我明白了,先生,我一直坚持使用 rand,认为它在随机生成时足够体面。但是,我现在将开始使用 mt19937 和 uniform_int_dist 之类的东西。
猜你喜欢
  • 2017-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多