在C中生成范围(-0.5,0.5)之间的随机数
Generate a random number between range (-0.5 , 0.5) in C
考虑以下 C 程序:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main()
{
srand(time(NULL));
for (int i = 0; i < 20; ++i) {
static float a = 0;
a = (rand() % 2001 - 1000) / 2.e3;
printf("%.4f ", a);
}
}
这将成功生成然后打印 -0.5 到 0.5 之间的随机数列表。例如:
./main.out
-0.2475 -0.3640 -0.3945 0.2995 0.0460 0.2230 -0.0340 0.1630 -0.2275 -0.3450 0.3560 -0.4335 -0.0025 -0.2980 -0.0505 -0.1815 0.3115 -0.4465 -0.1325 -0.2340
我检查了运算符的优先级,但仍然不明白表达式 (rand()%2001 - 1000)/2.e3
的工作原理。
(特别是负号是从哪里来的)
a = (rand() % 2001 - 1000) / 2.e3;
rand()
先计算
a = (rand() % 2001 - 1000) / 2.e3;
^^^^^^ int between `0` and `RAND_MAX` inclusive
然后模运算符生成一个介于 0
和 2000
之间的值。
a = ([0 .. 2000] - 1000) / 2.e3;
^^^^^^^^^^^ int
然后该值减去 1000
,成为 -1000
和 1000
之间的值
a = ([-1000 .. 1000]) / 2.e3;
^^^^^^^^^^^^^^^ int
然后,除以 2000.0
(或 2.e3
)在 -0.5
和 0.5
之间生成 double
a = [-0.5 .. 0.5];
^^^^^^^^^^^^^ double
我们来分析一下表达式(rand() % 2001 - 1000) / 2.e3
:
<stdlib.h>
中定义的 rand()
函数 returns int
类型的伪随机整数,范围在 0
到 RAND_MAX
包括在内。 RAND_MAX
也是在 <stdlib.h>
中定义的常量,其值至少为 32767
.
rand() % 2001
计算除以 2001
的余数。由于 rand()
为正数,因此结果是 0
到 2000
范围内的伪随机数,由于 2001
不除以 RAND_MAX
而造成小偏差均匀。
rand() % 2001 - 1000
被计算为 (rand() % 2001) - 1000
,结果的范围向负数移动 1000,即在 -1000
和 1000
之间包括在内。
来评估(rand() % 2001 - 1000) / 2.e3
,将前面步骤得到的值转换为类型double
并除以2.e3
,这将更具可读性2000.0
。因此,结果是 double
类型的浮点值,在 -0.5
和 0.5
之间包含 2001 个可能的不同值。
a = (rand() % 2001 - 1000) / 2.e3;
将此 double
值转换为 float
,即 a
的类型。 float
值在传递给 printf
时将隐式转换回类型 double
,这种转换在许多情况下不会产生完全相同的数字。
请注意,没有理由将 a
定义为 static
变量。
这是一个替代实现,它在相同的包含范围内产生更多不同的值,并且分布偏差略小:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL));
for (int i = 0; i < 20; ++i) {
double a = rand() / (double)RAND_MAX - 0.5;
printf("%f ", a);
}
printf("%\n");
return 0;
}
考虑以下 C 程序:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main()
{
srand(time(NULL));
for (int i = 0; i < 20; ++i) {
static float a = 0;
a = (rand() % 2001 - 1000) / 2.e3;
printf("%.4f ", a);
}
}
这将成功生成然后打印 -0.5 到 0.5 之间的随机数列表。例如:
./main.out
-0.2475 -0.3640 -0.3945 0.2995 0.0460 0.2230 -0.0340 0.1630 -0.2275 -0.3450 0.3560 -0.4335 -0.0025 -0.2980 -0.0505 -0.1815 0.3115 -0.4465 -0.1325 -0.2340
我检查了运算符的优先级,但仍然不明白表达式 (rand()%2001 - 1000)/2.e3
的工作原理。
(特别是负号是从哪里来的)
a = (rand() % 2001 - 1000) / 2.e3;
rand()
先计算
a = (rand() % 2001 - 1000) / 2.e3;
^^^^^^ int between `0` and `RAND_MAX` inclusive
然后模运算符生成一个介于 0
和 2000
之间的值。
a = ([0 .. 2000] - 1000) / 2.e3;
^^^^^^^^^^^ int
然后该值减去 1000
,成为 -1000
和 1000
a = ([-1000 .. 1000]) / 2.e3;
^^^^^^^^^^^^^^^ int
然后,除以 2000.0
(或 2.e3
)在 -0.5
和 0.5
double
a = [-0.5 .. 0.5];
^^^^^^^^^^^^^ double
我们来分析一下表达式(rand() % 2001 - 1000) / 2.e3
:
<stdlib.h>
中定义的rand()
函数 returnsint
类型的伪随机整数,范围在0
到RAND_MAX
包括在内。RAND_MAX
也是在<stdlib.h>
中定义的常量,其值至少为32767
.rand() % 2001
计算除以2001
的余数。由于rand()
为正数,因此结果是0
到2000
范围内的伪随机数,由于2001
不除以RAND_MAX
而造成小偏差均匀。rand() % 2001 - 1000
被计算为(rand() % 2001) - 1000
,结果的范围向负数移动 1000,即在-1000
和1000
之间包括在内。来评估
(rand() % 2001 - 1000) / 2.e3
,将前面步骤得到的值转换为类型double
并除以2.e3
,这将更具可读性2000.0
。因此,结果是double
类型的浮点值,在-0.5
和0.5
之间包含 2001 个可能的不同值。a = (rand() % 2001 - 1000) / 2.e3;
将此double
值转换为float
,即a
的类型。float
值在传递给printf
时将隐式转换回类型double
,这种转换在许多情况下不会产生完全相同的数字。请注意,没有理由将
a
定义为static
变量。
这是一个替代实现,它在相同的包含范围内产生更多不同的值,并且分布偏差略小:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL));
for (int i = 0; i < 20; ++i) {
double a = rand() / (double)RAND_MAX - 0.5;
printf("%f ", a);
}
printf("%\n");
return 0;
}