首页 /编程语言和算法/C/C++
 C++产生“大随机数”rand()+srand() Rand()函数能生成0,32767间的随机整数,对大随机分布不优秀
2023年3月20日 19:01

Rand()函数能生成[0,32767]间的随机整数,相当于15个随机的二进制位。
若需生成更大的整数,最佳方案应该是进行两次rand(),将两次rand()的值按二进制位拼接起来。

具体代码只能由VIP查看,请升级

此处<<为二进制左移运算,末位补0。第一次rand得到前15个二进制位,第二次rand得到后15个二进制位,用加法拼接得到30个二进制位,即范围为[0,2^30-1]=[0,1073741823][0,2^{30}-1]=[0,1073741823][0,2^30-1]=[0,1073741823]的大随机数。

P([2768,9999])\thereforeP([0,2767])\gtP([2768,9999])∴P([0,2767])>P([2768,9999])

令我们想要的范围为[0,N][0,N][0,N],当N远小于RAND_MAX的时候,比如[0,233]时,这种不均可以忽略。但比如范围达到[0,10000]时,概率就很不均匀了,使用本文上述的生成大随机数的方法,用更大的随机数对想要取的范围取膜,会使分布更加均匀,提高随机数的质量。

当然另一个思路是用判断语句强行舍弃赘余的部分,若发现取得的值在赘余部分就舍弃,能保证概率绝对均匀,其实对程序速度影响也不大(常数级别)但会令强迫症极度不爽。我们拼接成大数能减少赘余部分占比,因为也能优化这种舍弃赘余的思路。

很明显,这种方法还可以无限拼接扩展:<!--为二进制左移运算,末位补0。第一次rand得到前15个二进制位,第二次rand得到后15个二进制位,用加法拼接得到30个二进制位,即范围为[0,2^30-1]=[0,1073741823][0,2^{30}-1]=[0,1073741823][0,2^30-1]=[0,1073741823]的大随机数。<!--为二进制左移运算,末位补0。第一次rand得到前15个二进制位,第二次rand得到后15个二进制位,用加法拼接得到30个二进制位,即范围为[0,2^30-1]=[0,1073741823][0,2^{30}-1]=[0,1073741823][0,2^30-1]=[0,1073741823]的大随机数。<br-->

具体代码只能由VIP查看,请升级

superbigrandnum∈[0,2^45-1]=[0,35184372088831]
veryverysuperbigrandnum∈[0,2^60-1]=[0,1152921504606846975]veryverysuperbigrandnum\in[0,2^{60}-1]=[0,1152921504606846975]veryverysuperbigrandnum∈[0,2^60-1]=[0,1152921504606846975]
亦可与高精度运算技巧结合使用。

一些其它方法的问题:

具体代码只能由VIP查看,请升级

这样能保证分布大体均匀,但[0,1000000]之间很多数会是取不到的。
RAND_MAX为C++内置常量,值为32767,表示rand()函数能取到的最大值。1000000乘1/32767约等于31,明显27、28、29这些数字是永远随机不出来的,而且能随机出来的数字都位于1000000乘32767分之N的位置,绝对不符合随机数的要求。
而且也违背了祖师爷香农的信息守恒。数字本来就是以二进制方式储存的,何苦非得用十进制运算一位一位来拼凑。
这里给出代码:

具体代码只能由VIP查看,请升级

得出结果:

具体代码只能由VIP查看,请升级


 
全部回复(1)
  • 引用1楼

    PS:
    C/C++中 int、long、long long等取值范围

    unsigned int 0~4294967295
    int -2147483648~2147483647
    unsigned long 0~4294967295
    long -2147483648~2147483647
    long long的最大值:9223372036854775807
    long long的最小值:-9223372036854775808
    unsigned long long的最大值:18446744073709551615

    真正的随机数我想可以在以下地方找到:

    电压瞬间值
    城市车辆/人瞬间值
    天气各地温度+湿度+气温+阴晴值
    河水高度精确值


  • 首页 | 电脑版 |