我是靠谱客的博主 柔弱铃铛,最近开发中收集的这篇文章主要介绍C++ 使用rand()函数生成大随机数最佳方法较佳方法一些其它方法的问题:,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

C++ 使用rand函数生成大随机数的较佳方法

  • 较佳方法
  • 一些其它方法的问题:

较佳方法

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

 big_randnum = (rand()<<15) + rand();
 our_number=big_random%1000000;

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

大 随 机 数 = 第 一 次 r a n d ( ) 值 × 32768 + 第 二 次 r a n d ( ) 值 大随机数=第一次rand()值times32768+第二次rand()值 =rand()×32768+rand()
r a n d ( ) ∈ [ 0 , 32767 ] rand()in[0,32767] rand()[0,32767]
∴ 大 随 机 数 ∈ [ 0 , 1073741823 ] 且 分 布 均 匀 therefore大随机数in[0,1073741823]且分布均匀 [0,1073741823]
然后把取得的大随机数 对 实际需要的范围 取膜、调整即可。

可以发现,比如我们实际运用中需要的范围是 [ 0 , 9999 ] [0,9999] [0,9999],而我们用rand()%10000来生成,就会导致概率不均:
r a n d ( ) ∈ [ 0 , 32767 ] rand()in[0,32767] rand()[0,32767]
[ 0 , 32767 ] = [ 0 , 9999 ] ∪ [ 10000 , 19999 ] ∪ [ 20000 , 29999 ] ∪ [ 30000 , 32767 ] [0,32767]=[0,9999]cup[10000,19999]cup[20000,29999]cup[30000,32767] [0,32767]=[0,9999][10000,19999][20000,29999][30000,32767]
∴ P ( [ 0 , 2767 ] ) > P ( [ 2768 , 9999 ] ) therefore P([0,2767])gt P([2768,9999]) P([0,2767])>P([2768,9999])
令我们想要的范围为 [ 0 , N ] [0,N] [0,N],当N远小于RAND_MAX的时候,比如[0,233]时,这种不均可以忽略。但比如范围达到[0,10000]时,概率就很不均匀了,使用本文上述的生成大随机数的方法,用更大的随机数对想要取的范围取膜,会使分布更加均匀,提高随机数的质量。
当然另一个思路是用判断语句强行舍弃赘余的部分,若发现取得的值在赘余部分就舍弃,能保证概率绝对均匀,其实对程序速度影响也不大(常数级别)但会令强迫症极度不爽。我们拼接成大数能减少赘余部分占比,因为也能优化这种舍弃赘余的思路。

很明显,这种方法还可以无限拼接扩展:

superbig_randnum=(rand()<<30) + (rand()<<15) + rand();
veryverysuperbig_randnum=(rand()<<45) + (rand()<<30) + (rand()<<15) + rand();
// 依次类推

s u p e r b i g r a n d n u m ∈ [ 0 , 2 45 − 1 ] = [ 0 , 35184372088831 ] superbigrandnumin[0,2^{45}-1]=[0,35184372088831] superbigrandnum[0,2451]=[0,35184372088831]
v e r y v e r y s u p e r b i g r a n d n u m ∈ [ 0 , 2 60 − 1 ] = [ 0 , 1152921504606846975 ] veryverysuperbigrandnumin[0,2^{60}-1]=[0,1152921504606846975] veryverysuperbigrandnum[0,2601]=[0,1152921504606846975]
亦可与高精度运算技巧结合使用。

一些其它方法的问题:

(int) ((double)rand() / RAND_MAX) * 1000000;

这样能保证分布大体均匀,但[0,1000000]之间很多数会是取不到的。
RAND_MAX为C++内置常量,值为32767,表示rand()函数能取到的最大值。1000000乘1/32767约等于31,明显27、28、29这些数字是永远随机不出来的,而且能随机出来的数字都位于1000000乘32767分之N的位置,绝对不符合随机数的要求。
而且也违背了祖师爷香农的信息守恒。

#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <cmath>

using namespace std;

void main(){
	int num;
	int totalNum;
	srand((unsigned int)(time(NULL)));
	for(int i = 0; i < 10; i++){
		totalNum = 0;
		for(int j = 0; j < 6; j++){
			num = rand() % 10;
			totalNum += num * pow(10, j);
		}
		cout << totalNum << endl;
	}
}

杀鸡焉用牛刀,数字本来就是以二进制方式储存的,何苦非得用十进制运算一位一位来拼凑。除法和取余运算%的效率真的非常低,这都%了多少次10了这?看着好难受啊。

最后

以上就是柔弱铃铛为你收集整理的C++ 使用rand()函数生成大随机数最佳方法较佳方法一些其它方法的问题:的全部内容,希望文章能够帮你解决C++ 使用rand()函数生成大随机数最佳方法较佳方法一些其它方法的问题:所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部