clang - 糟糕的 rand() 实现
clang - poor rand() implementation
我做了一个 Pong 游戏,我必须 运行 控制球的投掷。为此,我使用了内置的 运行dom 数字生成器并在 Ubuntu/GCC 中获得了不错的结果。在将代码移植到 Mac 并编译时,球只会在一个方向上投影,这意味着 clang 中的 rand()
函数没有按预期工作。
我已经恢复到自定义数字生成器,但这是游戏中最初有问题的代码:
srand(time(NULL));
float ang = ((float)rand())/RAND_MAX * 120 - 60;
int side = (int)(((float)rand())/RAND_MAX * 2);
经过进一步检查,我创建了以下测试程序并在两个平台上编译和运行它。
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv) {
while (1) {
int now = time(NULL);
printf("Time now is %d\n", now);
srand(now);
int random = rand();
printf("Random number generated is %d\n", random);
sleep(1);
}
}
结果(根据 RAND_MAX
制表和计算,在两个系统上都是 2147483647
)如下:
结果不言自明。虽然在 clang 版本中有 运行domness,但与 RAND_MAX
的值相比,运行domness 非常差,与标准相比,标准偏差为 0 证明了这一点gcc 上的偏差为 0.328。
rand()
在 clang 上表现不佳的原因是什么?我还想在头文件中看到这个函数的参考实现。这似乎是不标准的,并且我一定不是唯一一个 运行 在将使用此方法的程序移植到 Mac 时遇到问题的人。 using/relying 在 运行dom 数字生成器上时,还有哪些其他设计原则是好的做法?
行为不当的原因:
所以我不知道苹果针对兰德的 clang 实现的确切实现,但我知道它是作为 LCG 或线性同余生成器完成的。它的工作方式基本上是一个公式:
在公式中,就是RAND_MAX
,和是编译器定义的一些常量。 Apple 的 Clang 分别使用了 16807
和 0
。
rand()
的 return 是 ,rand()
的最后一个 return 或您输入 srand()
的值将是.
如果你只想要一个有点随机的数字序列,这很好用,因为它最终会 return 0
和 RAND_MAX
之间的所有数字,没有人类明显的模式。
但是,通过一些计算,您可以很容易地发现,如果您只是将连续的数字序列放在该公式中 的位置(您就是这样做的),就会出现一些问题。 rand()
的每次调用之间的差异将恰好等于 ,除非 实际上接近 RAND_MAX
.
正确的使用方法:
通过rand()
函数获取随机数的正确方法是在开始时只调用一次srand()
,并且在循环中只使用rand()
。
或者,您可以查找许多其他随机生成公式,您可能可以在这里找到一些:How to generate a random int in C?
我做了一个 Pong 游戏,我必须 运行 控制球的投掷。为此,我使用了内置的 运行dom 数字生成器并在 Ubuntu/GCC 中获得了不错的结果。在将代码移植到 Mac 并编译时,球只会在一个方向上投影,这意味着 clang 中的 rand()
函数没有按预期工作。
我已经恢复到自定义数字生成器,但这是游戏中最初有问题的代码:
srand(time(NULL));
float ang = ((float)rand())/RAND_MAX * 120 - 60;
int side = (int)(((float)rand())/RAND_MAX * 2);
经过进一步检查,我创建了以下测试程序并在两个平台上编译和运行它。
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv) {
while (1) {
int now = time(NULL);
printf("Time now is %d\n", now);
srand(now);
int random = rand();
printf("Random number generated is %d\n", random);
sleep(1);
}
}
结果(根据 RAND_MAX
制表和计算,在两个系统上都是 2147483647
)如下:
结果不言自明。虽然在 clang 版本中有 运行domness,但与 RAND_MAX
的值相比,运行domness 非常差,与标准相比,标准偏差为 0 证明了这一点gcc 上的偏差为 0.328。
rand()
在 clang 上表现不佳的原因是什么?我还想在头文件中看到这个函数的参考实现。这似乎是不标准的,并且我一定不是唯一一个 运行 在将使用此方法的程序移植到 Mac 时遇到问题的人。 using/relying 在 运行dom 数字生成器上时,还有哪些其他设计原则是好的做法?
行为不当的原因:
所以我不知道苹果针对兰德的 clang 实现的确切实现,但我知道它是作为 LCG 或线性同余生成器完成的。它的工作方式基本上是一个公式:
在公式中,RAND_MAX
,16807
和 0
。
rand()
的 return 是 rand()
的最后一个 return 或您输入 srand()
的值将是
如果你只想要一个有点随机的数字序列,这很好用,因为它最终会 return 0
和 RAND_MAX
之间的所有数字,没有人类明显的模式。
但是,通过一些计算,您可以很容易地发现,如果您只是将连续的数字序列放在该公式中 rand()
的每次调用之间的差异将恰好等于 RAND_MAX
.
正确的使用方法:
通过rand()
函数获取随机数的正确方法是在开始时只调用一次srand()
,并且在循环中只使用rand()
。
或者,您可以查找许多其他随机生成公式,您可能可以在这里找到一些:How to generate a random int in C?