打印随机数会返回负数。(/dev/urandom)

3

我已经编写了一段源代码,用于在指定范围内打印随机数。但是它也返回了一些负数,这正常吗?如果不是,我该如何纠正它?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main( int argc, char* argv[])

{        

    int fd, n;
    fd = open("/dev/urandom", O_RDONLY);
    if(fd == -1)
    printf("ERROR: Cannot Open %s\n",argv[1]);

    read(fd, &n, sizeof(n));                      //n=random number
    printf("%d\n",1+n%6);                         //limiting n 

    /* 1+n%6 should give me random numbers only between
       1-6(correct me if I'm wrong),
       but somehow it even gives negative numbers*/        

    close(fd);

}

1
这就是随机性的问题。你永远无法确定。 - thyrgle
printf("%d\n",1+abs(n%6)); 这个对我的需求很有帮助。同时使用无符号整数也可以。谢谢大家。 - Pavitar
1
顺便提一下,在固定范围内获取均匀分布的随机数,取模运算不是可靠的方法。这会产生偏差,因为6不能被UINT_MAX平均整除。 - R.. GitHub STOP HELPING ICE
3个回答

1

1 + n % 6并不能神奇地将结果限制在0-6之间。运行代码来查看。

#include <stdio.h>

int main(int argc, char* argv[]) {
  printf("%d\n", 1 + (-23) % 6);

  return 0;
}

1

哇,即使是我也认为模运算符在应用时像

c=a%b

限制c在整数[0,b-1]之间。

但正如K&R所写(第2版第39页):

表达式x % y产生当x被y整除时的余数,因此在y完全整除x时为零。

因此,实际上发生了什么是:

c = sign(a) * ( abs(a)%abs(b) )

(其中对于a<0,sign(a)=-1,对于a>=0,sign(a)=+1)

如果有人能够指出一本书或C标准中关于这种行为的实际参考资料,那就太好了。这是我在使用GCC v4.4.1进行实验后找到的结论。

感谢这个好问题。你让我对C模数运算符的理解更清晰了。


遗憾的是,这种错误行为是C99所必需的,并且早期版本的C标准允许(作为可选的脑损伤)。如果您正在执行2的幂次方取模运算,则解决此问题的方法是使用位与运算符而不是“%”运算符。否则,您将被迫编写丑陋、缓慢的代码来进行补偿... - R.. GitHub STOP HELPING ICE

1

如果你读取的随机数是负数(这是可能的),那么它的模也可能是负数。为了确保结果在你想要的范围内,你应该使用无符号整数。

更多信息可以在这里找到。


6
注意,使用 abs() 可能会使其偏差。改用无符号整数。 - Ignacio Vazquez-Abrams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接