【问题标题】:Why is rand() giving me negative numbers?为什么 rand() 给我负数?
【发布时间】:2021-02-26 15:50:15
【问题描述】:

我正在尝试使 rand_draw 保持 0-8 之间的随机正数。但是这段代码在某些迭代中不断给出负数。发生了什么事?

srand(time(0));
int draw_count = 8;
int rand_draw = (2 * rand()) % draw_count;
cout << rand_draw << endl;

【问题讨论】:

  • 为什么是2 * rand()?这可能会给你溢出,因此是负数。
  • rand() 返回一个介于 0 和 RAND_MAX 之间的值,通常与 INT_MAX 相同。所以一半时间2 * rand() 会溢出。这是未定义的行为,但结果通常是负值。
  • 如果它没有给你溢出,你永远不会得到奇数。无论如何,除非绝对没有其他方法,否则不要在 C++ 中使用 rand()。使用std::uniform_int_distribution&lt;int&gt;
  • 这不是对 C++ 的介绍,而是古代 C++ 的历史。我不明白为什么今天要教这个。你被教导编写遗留代码。这个函数不会通过任何严格的代码审查。
  • @ThomasSablik • 让今天的新程序员为明天的未来编写昨天的遗留代码!我满怀期待地期待过去!

标签: c++ random


【解决方案1】:

根据cppreference,rand():

返回一个介于​0​和 RAND_MAX(包括 0 和 RAND_MAX)之间的伪随机整数值。

RAND_MAX 的值是实现定义的,但很可能是int 中可以表示的最大值。通过将您从rand() 获得的值加倍,结果可能会溢出为负数。这实际上是未定义的行为。

我认为没有理由将rand() 的返回值翻倍。你可以很简单地纠正这个问题:

int rand_draw = rand() % (draw_count + 1);

这将为您提供 0 到 8 之间的随机值,正如您指定的那样。

但在现代 C++ 中,使用 C++ 标准库中的 uniform_int_distribution 是一种更好的方法。这是链接页面中的示例,经过修改以显示您指定的范围:

#include <random>
#include <iostream>
 
int main()
{
    std::random_device rd;  //Will be used to obtain a seed for the random number engine
    std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
    std::uniform_int_distribution<> distrib(0, 8);
 
    for (int n=0; n<10; ++n)
        //Use `distrib` to transform the random unsigned int generated by gen into an int in [0, 8]
        std::cout << distrib(gen) << ' ';
    std::cout << '\n';
}

【讨论】:

    【解决方案2】:

    rand() 函数将在 [0, RAND_MAX) 范围内生成一个随机数。 RAND_MAX 是一个很大的数字。 更多细节在link中讨论

    当您使用 2*rand() 时,基本上是将生成的数字向左移动 1 位。如果生成的数字足够大,从左边算起第二位为 1,那么在向左移动后,您将生成一个负数。

    这是一个例子: 假设生成的十六进制数是 0x70000011。 这个数字的最高四位是 0111,左移 1 位后,可以看到符号位在变化。 然后你尝试使用导致负数的 % 操作。

    1. rand() % draw_count -> 生成数字 [0, draw_count)
    2. (rand() % draw_count) + draw_count -> 生成数字 [draw_count, 2* draw_count)
    3. rand() % (2draw_count) -> 生成数字 [0, 2 draw_count)

    【讨论】:

      【解决方案3】:

      我想出了一个解决方案,因为我只能使用 rand() 函数。我只是在之后添加了一个 if 语句来检查它是否是偶数,如果是,则将变量设置为 rand_draw,如果不是,则递增 1。

      int rand_draw = rand() % draw_count;
      if (rand_draw % 2 == 0)
      {
          rand_draw = rand_draw;
      }
      else
      {
          rand_draw += 1;
      }
      

      【讨论】:

      • @ThomasSablik 很好,只要this one 会...
      • 你想要随机的、积极的,甚至?那应该是问题所在。 int rand_draw = (rand() % 4) *2; 因为在不会发生加倍溢出之前应用了模数。请注意,我们必须将随机数的范围减半。
      猜你喜欢
      • 2015-08-29
      • 2023-02-25
      • 1970-01-01
      • 2021-02-11
      • 2019-07-15
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多