c语言中printf("%c",(i+64)-'0');,C语言|生成[0, 2^64-1]范围内的随机整数

| 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

往期瞎写

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值