| No.27
C语言的rand()函数只能生成[0, 2^15-1]范围内的随机整数,也就是15位数。大多数时候这已经够用了,但我们仍有需要更大范围的随机数的时候。
rand()返回的是一个32位的int型,但是其生成的随机数范围却只有[0, 32767],32767即2^15-1。连多搞一位到65535即2^16-1都不肯。这有点奇怪。。
我们要做的是以rand()为基础,得到生成[0, 2^64-1]范围内的随机整数的函数。
00
—
[0, 2^16-1]
rand()已经随机生成了15位,那我们再在这15位的基础上添加随机生成的1位,就相当于生成了16位的随机数了。
unsigned int rand16bits(){int r1 = rand(), r2 = rand();int offset = (r2 & 1) << 15;return r1 + offset;}
生成两个随机数r1和r2。r1的范围就是rand()的范围[0, 32767]。r2的用处是根据其奇偶确定offset的值。
如果r2是偶数,r2&1为0,0<<15也为0。如果r2是奇数,r2&1为1,1<<15为32768(2^15=32768)。offset的取值只有两个:0或32768。如果从二进制来看,offset的16位只有0或1两个可能,其他位全为0。
r1的低15位是随机的,r2的第16位是随机的。把他们直接相加,得到的二进制数也是随机的。这个二进制数对应的十进制数也是随机的。
人脑运行代码验证:什么时候得到随机数0?只有offset为0并且r1为0这一种情况。什么时候得到随机数65535?只有offset为32768并且r1为32767这一种情况。
多想几次就明白了,[0, 65535]中的任一个数都只有一种情况对应,所以这些数生成的几率是均等的。
01
—
[0, 2^32-1]
有了16位随机数做基础,32位随机数就很简单了。
unsigned int rand32bits(){return (rand16bits() << 16) + rand16bits();}
直接把一个16位随机数左移16位。这样看来高16位就是随机数,低16位全为0。再加上一个16位随机数,就得到32位随机数。
要注意的是+的优先级比<
02
—
[0, 2^64-1]
沿用从16位随机数到32位随机数的思路。注意要用unsigned long long声明64位数。int只有32位本来就是不够储存64位数的。
unsigned long long rand64bits(){unsigned long long high = rand32bits();unsigned long long low = rand32bits();return (high << 32) + low;}
再次提醒,+的优先级比<
其他各种范围的随机数,在此基础上操作就行了。
03
—
验证
int main(){srand((unsigned)time(NULL));unsigned int a = 0xffffffff;unsigned long long b = a, c = a, d = (b << 32)+ c;printf("%llu %016I64x %d\n", d, d, sizeof(d));//%I64x可打印64位数的16进制 %x只能打印32位数return 0;}
经过分析和有限次的测试,暂未发现错误。。
04
—
往期瞎写