【问题标题】:Why does rand() % 7 always return 0?为什么 rand() % 7 总是返回 0?
【发布时间】:2011-12-13 14:00:53
【问题描述】:

这似乎是一个非常奇怪的问题:

这是我的代码:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        srand((unsigned int)time(NULL));
        int newRandomNumber = 0;
        newRandomNumber = rand() % 7;
        NSLog(@"%d", rand() % 7); //This prints out what I expected
        NSLog(@"newRandomNumber = %d", newRandomNumber); // This always prints out 0!
    }
    return 0;
}

如果我替换那一行

newRandomNumber = rand() % 7

newRandomNumber = rand() % 8

一切都很完美。为什么会这样?

【问题讨论】:

  • 无法在C 中重现您的问题。
  • 我可以在 Objective-C 中重现这一点。即使是srand([[NSDate date] timeIntervalSince1970])。但是将较小的整数传递给srand() 似乎可以解决它。
  • 如果你打印 rand() 会得到什么?你每次都得到相同的数字,还是只得到与 0 模 7 一致的数字?
  • 您是否尝试过多次迭代?我猜第一个 rand() 值总是 7 的倍数。

标签: objective-c c random


【解决方案1】:

这似乎不太可能,但运行一些测试,在一个 srand 之后,第一个 rand 似乎总是可以被 7 整除,至少在一个 int 大小的变量中。

在几次运行中,我得到了 1303562743、2119476443 和 2120232758,所有这些都是 mod 7 到 0。

第二个rand() 有效,因为它是第二个rand()。在您的第一个 rand() 之前添加一个 rand()... 或者更好的是,使用更好的随机数生成器 randomarc4rand(如果有)。

另请参阅堆栈溢出问题Why is (rand() % anything) always 0 in C++?

【讨论】:

  • Grady player 几乎可以回答您的问题:这是因为这是您第一次拨打一个并非真正随机生成的号码。然而,另一点和一个事实仍然让我感到困惑:
  • (1) 如果您根本看不到stand(),系统将始终在第一次调用时生成正常的号码。在我的系统上,一个“next”变量跟踪下一个 rand() 值,如果没有 srand() 调用发生,next 被播种为 1。返回的值是在添加和乘以系统常数并取结果 mod 32,768 之后。这意味着对于第一次调用时选择的某个模数用户,您仍然会得到 0,在您的情况下为 7,但它可能是另一个数字。
  • (2) 文章讨论了可移植性问题,使用模数不会影响这些问题。本质上它指出 time_t 可能无法正确转换为无符号整数;并且最好不要使用 mod,而是乘以得到您想要的范围(在您的情况下,* 7/RAND_MAX)。作为我不知道的这个目标C,这可能是一个问题,但我对此表示怀疑。令我感到困惑的是,在 update_tines() 中的每个全局定时器中断(在任何情况下,在 LINUX 2.6.xx 内核上),报告的 time() 值都会在内部更新,这应该在第二个滴答之间发生。
  • 为什么 srand() 会报告回来,正如你所说的那样,基本上相当于 7 秒的增量(我知道这不是它的确切含义,但它似乎相关),让我抓狂我的头。
【解决方案2】:

嗯,这个

int seed;
for(seed = 1; seed < 10; seed++) {
    srand(seed);
    printf("%4d %16d\n", seed, rand());
}

打印

   1            16807
   2            33614
   3            50421
   4            67228
   5            84035
   6           100842
   7           117649
   8           134456
   9           151263

这让我觉得rand() = seed * 16807

维基百科文章 Linear congruential generator 证实 CarbonLib 确实使用 Xn+1 = Xn * 16807 来生成随机数。

【讨论】:

  • 我在 Linux 2.6.32 上运行的公式比较复杂。它的形式为 next = ( next * const_1 + const_2) % 32,768。显然,也许您对平台的公式进行了逆向工程。它依赖于实现,尽管常量在扭曲和转动之后通常接近质数。
  • 虽然不太可能先让它们简单地成为没有其他转换的余数。
  • LCG 的选择太糟糕了
  • 你漏掉的部分:因为16807 % 7 == 0(n * 16807) % 7 == 0也一样,只要你没有出现整数溢出。
猜你喜欢
  • 2021-01-24
  • 2016-09-16
  • 2020-05-25
  • 2013-02-26
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多