在互联网时代,经常有产生一个不重复的随机数的应用场景。
比如点击领用优惠券,产生一个10000 以内的随机数。该数字发到用户手机上,作为验证凭证。
每次该数字需要有如下要求:
1:每次都是随机产生,用户不能轻易猜测到下一个验证码。
2:同一个数字,只会出现一次。不会存在多个用户领用同一个验证码的情况。
基于上述类似场景,可以采用《线性同余产生随机数》算法,每次生成一个不重复的随机数。
线性同余产生随机数算法解析:
Xn+1 = ( aXn + c ) mod m ,n >= 0
其中: 0 < m ;0 <= a<m ; 0 <=c<m
开始指定一个X0( 0<=X0<m ),依赖上次的值Xn,每次得到一个数Xn+1。根据这个算法所求的随机数序列{X0,X1,...Xn},称作线性同余序列。
同余序列总是进入一个循环,它最终必定在n个数之间无休止的重复循环。它的最大循环周期为m。
得到最大的周期m的条件如下:
(1)c与m为互质数。
(2)对于整除m的每个素数p,b=a-1是p的倍数。
(3)如果m是4的倍数,则b也是4的倍数。
以取10000个 随机数为例,m = 10000;按最大的周期条件设定c = 3; a = 21; x0=4。
代码如下:
1 public static void RandomGenerator(ref long previousVaule) 2 { 3 //Xn+1 = ( aXn + c ) mod m ,n >= 0 4 long m = 10000L; 5 long c = 3L; 6 long a = 21L; 7 8 previousVaule = (a * previousVaule + c) % m; 9 }
long ab = 4; HashSet<long> hash = new HashSet<long>(); for (int i = 0; i < 10000; i++) { RandomGenerator(ref ab); hash.Add(ab); Console.WriteLine(ab); } Console.WriteLine("总数:"+hash.Count);
运行结果:
经测试可以验证,10000次随机穷举所有<10000的数字现。现实应用中,还要解决分布式情况下,对上次的值Xn依赖的争用问题。
算法参考:http://www.asmedu.net/algorithm.jsp?index=46