我正在阅读
C FAQ并在
question中发现它建议我使用rand()/(RAND_MAX / N 1)而不是更流行的方式是rand()%N.
原因是当N是一个低数字rand()%N将只使用rand()中的几个位.
我在Windows和Linux上测试了N为2的不同方法但是没有注意到差异.
#include <stdio.h> #include <stdlib.h> #include <time.h> #define N 2 int main(void) { srand(0); printf("rand() %% N:\n"); for (int i = 0; i < 40; ++i) { printf("%d ",rand() % N); } putchar('\n'); srand(0); printf("rand() / (RAND_MAX / N + 1):\n"); for (int i = 0; i < 40; ++i) { printf("%d ",rand() / (RAND_MAX / N + 1)); } putchar('\n'); return 0; }
输出是这个(在我的gnu / linux机器上):
rand() % N: 1 0 1 1 1 1 0 0 1 1 0 1 0 1 1 0 0 0 0 0 1 0 1 1 0 0 0 1 1 1 1 0 0 0 1 1 1 0 1 0 rand() / (RAND_MAX / N + 1): 1 0 1 1 1 0 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 0 0 1 0 1 1 1 0 1 1 0 1 0 1
两种选择对我来说都是完全随机的.甚至看起来第二种方法比兰特%N更差.
我应该使用rand()%N还是rand()/(RAND_MAX / N 1)?
解决方法
如果N是2的幂,则使用余数技术通常是安全的(RAND_MAX通常是2的幂-1,因此整个范围具有两个长度的幂).更一般地,N必须除以rand()的范围以避免偏差.
否则,无论rand()的质量如何,都会遇到this problem.简而言之,问题在于你将该范围切割成长度为N的多个“部分”,如果N不分割范围则最后部分将不完整.因此,从该部分“切断”的数字不太可能发生,因为它们可以从中生成更少的“部分”.
不幸的是rand()/(RAND_MAX / N 1)也被破坏了(几乎以同样的方式),所以真正的答案是:不要使用它们中的任何一个.
上面提到的问题非常重要,除非Y除以X,否则无法在Y结果上均匀分布X个不同的值.您可以通过拒绝一部分随机样本来修复它,使Y除以新的X.