这个答案主要适用于在 x86_64 机器上寻找随机双打的人。
作为一个长期的 C 用户(自 1980 年代后期以来),我不再关心当天的 RAND_MAX 值是多少。
另外,srand(time(NULL) 向我表明,这些数字是由一些(至少对我而言)质量未知的准随机数生成器生成的。所有这一切,虽然您距离现代 x86_64 机器上的 CPU 随机数只有 1 条汇编指令。
因此,下面的代码通过内部函数使用rdrand,已知它是一个完整的 64 位随机数作为随机源。这样,至少,您有足够的位来生成双精度数而无需多言。如果 - 相反 - 您选择了 C 库 rand() 并且它返回 32 位值,那么您可能没有足够的位来容纳 64 位浮点数。并且在 Ansi C 中没有 randl(), randul() 或类似名称,afaik。
但是 - 如果您查看 _rdrand_step() 内在函数的签名,则该指令似乎在某些条件下可能会失败。 (有人说,负载相关)。因此,在下面的代码中,围绕内部调用编写一个 while() 循环或类似的东西可能(也可能不是)是个好主意。
#include <stdio.h>
#include <stdint.h>
#include <immintrin.h>
#include <float.h>
int randomf64(double minVal, double maxVal, double* out) {
if (NULL == out)
return 0;
uint64_t result = 0ULL;
// cast in next line works for amd64 (x86_64) on linux at least.
int rc = _rdrand64_step((unsigned long long*)&result);
if(rc) {
double unscaled = (double)result/(double)UINT64_MAX;
*out = minVal + (maxVal - minVal) * unscaled;
return 1;
}
return 0;
}
int main(int argc, const char* argv[]) {
size_t nvals = 1;
if(argc > 1) {
nvals = atol(argv[1]);
}
// We want to see if all that "can fail under stress" thing happens...
double *values = malloc(nvals * sizeof(double));
if (NULL != values) {
for(size_t i = 0; i < nvals; ++i ) {
if(!randomf64(-100.0,100.0, &values[i])) {
printf("boom! after %lu random numbers generated.\n",
i);
free(values);
exit(-1);
}
}
for(size_t i = 0; i < nvals; ++i) {
int Digs = DECIMAL_DIG;
printf("%lu %.*e\n", i, Digs, values[i]);
}
free(values);
}
return 0;
}
如果你提供一个整数作为命令行参数,它会生成一个相应的
随机双精度数并将它们存储在堆分配的数组中。
这允许测试是否可能发生“零星失败”。我尝试了几次,一次最多创建了 1E6 个值,但从未失败(在一些便宜的 AMD CPU 上)。
为了编译这个,例如用clang,我用过:
clang -mrdrnd -O3 -std=c17 -o r64i r64intrin.c
请注意,您必须使用 -mrdrnd 启用内部函数才能使编译器满意。