【问题标题】:How can I get rid of the warning with rand()? (C++)如何摆脱 rand() 的警告? (C++)
【发布时间】:2010-10-23 12:14:40
【问题描述】:

每当我在 C++ 中使用 rand 函数时:

#include<iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;
int main(){
srand(time(0));
int n=(rand()%6)+1;
cout<<"The dice roll is "<<n<<"."<<endl;
}

我在第 5 行收到关于从 time_t 转换为 int 的警告:

srand(time(0));

有什么办法可以消除这个警告吗?

【问题讨论】:

  • 你应该在 C++ 代码中使用
  • 为什么要删除 C++ 的 C 标签?问题是关于 srand() 和 time(),它们来自 C 语言。

标签: c++ time random standard-library seed


【解决方案1】:

实际上,您应该使用unsigned int with srand()

srand((unsigned) time(0));

【讨论】:

  • 学究式注释 - 使用 static_cast 公式进行演员表对 grep 更友好。
【解决方案2】:

换个说法,这段代码:

rand()%6

通常被认为是一种不好的做法。 rand() 的低位比高位的随机性要小得多。如果你这样做,你会得到更好的随机性:

(rand() >> 8)%6

例如。

编辑:

有关此的更多详细信息,请参阅this note 以及来自Dr. Dobbs 期刊的这篇文章,其中至少暗示了原因:

注意:不要使用

  y = rand()  %  M;

因为这侧重于低位 兰德()。对于线性同余随机 数字生成器,其中 rand() 经常 是,较低的字节要少得多 随机比更高的字节。实际上 0 和 1 之间的最低位周期。 因此 rand() 可能在偶数和 奇怪(试试看)。注意 rand() 不 必须是线性同余 随机数发生器。它是 完全允许它是 没有的更好的东西 这个问题。

DDJ:

最重要的一点是 从输出的低位 通常(线性同余)随机 数字生成器是最少的 “随机的。”也就是说,在 低位是常见的。因此, 例行程序的输出在您的 讨论不足为奇。还有,它 依靠鞋面是可以避免的 确定整数的位 返回。

例如,如果您想选择一个随机的“真”或“假”值,并且您使用了代码:

rand() % 2

那么你最终可能会看到结果的模式:

1,0,1,0,1,0,1,0,1,0(等)

这显然不是随机的,但它是可能正在使用的线性同余生成器的一个属性。一个更好的方案(对于 C++)可能是使用 Boost.Random 库,它支持所有类型的可插拔随机生成器(包括没有这个缺陷的 Mersenne Twister)。

【讨论】:

  • 能否详细说明(我对 C++ 还很陌生)
  • 如果您想详细说明为什么某些位比其他位更随机,我不知道。听起来不错!但是 >> 是一个转变。不要与它的其他用途混淆,您可能已经见过 (cin>>some_string_var)。想想二进制中的数字向右移动了 8 位,左边是零。所以 0110 1101 0001 0010 会变成 0000 0000 0110 1101。
【解决方案3】:

使用显式强制转换来消除警告:

srand((int)time(0));

【讨论】:

  • 耶奇。如果 time_t 为 double 且 int 为 32 位,则会出现 Y2038 问题。
  • 没有 Y2038 问题 - 您对确切的日期值并不真正感兴趣,只是一些半随机数来作为随机数生成器的种子。
  • 你错了;一旦 time_t 值超过 2^31 - 1,种子就会固定在那里。
  • 实际上,如果 time_t 值超过 2^31-1 你不知道种子是什么——如果浮点数/双精度数的整数部分不能用整数类型表示,这是未定义的行为.
  • 我真的希望 time_t 不会变成双倍。 64 位 int,当然,但我害怕认为如果将 time_t 转换为整数类型会产生未定义的行为,会破坏多少代码......
【解决方案4】:

两个旁注:

  • 在 C++ 中包含 C 标头的标准方法如下:#include &lt;cstdio&gt;
  • 传递给time()的参数是一个指针,很多人认为NULL是一个比0更具可读性的空指针。

【讨论】:

  • 在 C++ 中,很多人(包括 Dr Stroustrup)更喜欢使用 0 作为空指针。
【解决方案5】:

要消除警告,您应该使用静态强制转换为无符号整数。

srand(static_cast<unsigned int>(time(0)));

在相关说明中,rand 的结果应向右移动以消除低位中的任何偏差。

int n = ((rand() >> 8) % 6) + 1;

最后,在 C++ 中,C 时间库和标准库应该包含为:

#include <ctime>
#include <cstdlib>

这会将函数放置在适当的命名空间“std”中。

【讨论】:

    【解决方案6】:

    还有,

     rand() % 6
    

    将引入一个小的偏差。由于 RAND_MAX % 6 为 1,因此零和一的出现频率将略高于二到六。在这种情况下,每 5461 次返回较高的数字,它们就会返回 5462 次,因此您可能不会注意到它。但是,如果您想要的数字范围很大,则偏差可能很大。例如,如果您使用rand() % 32000,则 0 - 767 范围内的数字出现的频率将是 768 - 32000 的两倍。

    【讨论】:

    • RAND_MAX % 6 是一个介于 0 和 5 之间的数字,这就是你所能说的。它是一个实现提供的宏是有原因的。
    • 具体情况可能因实现而异,但基本原理是正确的。 (此外,RAND_MAX == 32767 在 PC 上非常接近普遍存在。即使您的库使用不同的值,RAND_MAX % 6 == 5(无偏差所需)的可能性也很低)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    • 2021-11-08
    • 1970-01-01
    相关资源
    最近更新 更多