团购码,你知多少?——线性同余产生随机数

在互联网时代,经常会有产生【随机数】的应用场景。

比如说最常见的团购业务,用户购买一张团购券,然后客户的手机中会接收到一个随机的团购码。客户拿着这个团购码去门店验证消费。

相面大家都对上面的这种方式比较熟悉。如果站上技术的角度,我们来分析一下这个【团购码】其实还是有很多细节在里面的。接下来我们来对这部分细节进行探讨。

 

假设用点击领用团购码,产生一个10000 以内的随机数。该数字发到用户手机上,作为验证凭证。

那么这个团购码需要满足下面的几个条件:

1:每次都是随机产生,用户不能轻易猜测到下一个验证码。

2:团购码的数值范围必需【00001,10000】。——实际中这个数字会比较大。

3:用户领用的团购码是决对唯一的,即产生的每个数字,只会出现一次。不会存在多个用户领用同一个验证码的情况。

上面条件的技术难点在于如何生成不重复的随机数

大家知道,一般我们用的编程语言所提供的随机数方法,都不能保证下一次的随机数和前面的不重复。即我们生成了100个随机数里面,就可能会有N个是重复。

那么如何保证其不重复性? 很容易想到的方案是,每次生成一个新的随机数后,再去和前面的所有的随机数进行比较,如果重复则抛弃。

但是这样做好么?假设要生成1000个随机数,每次都和前面的进行比较好像问题不大。要是要1亿的范围呢?

我有个朋友正好在一家知明的团购公司工作,我向他了解下他们公司生成团购码的方法。

总体思路是:

1:生成一批待用的码放在码池中。用的是编程语言所提供的随机数方法。

2:用户领用码后,生成一条领用记录,并且码池中除非该码。

3:定期检查码池,生成新的码放入池中。

同样面临重复码的问题。如果两个用户a,b 在不同时间段领到了相同的团购码。用户a 比用户 b 更先一步去门店消费,然后更新该团购码的状态。那么用户b的那个码也会更新,则用户b来消费的时候会发现该码已经被用了。

他们如何解决这个问题,在步骤1 批量生成码的时想,先check码池的所有记录是否重复。当然最好再和用户领用记录check一下。

这样会带来性能上的很大消耗。或许可以想一些办法可以减少这方面的损失,比如码池放更多的码,过期的领用的记录及时清理。

更多的具体细节,不再去深入。

 

上面的做法,多多少少不是很理想。没有在关键点上解决问题——用一种算法每次生成一个和前面不重复的随机数。

 

基于上述类似场景,提供一个《线性同余产生随机数》算法,每次生成一个不重复的随机数。

算法参考:http://www.asmedu.net/algorithm.jsp?index=46

 

线性同余产生随机数算法解析:

Xn+1 = ( a * Xn + 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依赖的争用问题。

最后,大家可能还是有疑问。这样的随机码冒似可以破解。这批随机码是有规率的对吗?

所以最后对每次批量生成的码,要再把它们的顺序打乱一下再存到池中。

最重要的是下批量生成的码将不会和前面的重复。

 

作者:张日海

posted on 2014-11-03 13:44  张日海  阅读(1174)  评论(0编辑  收藏  举报

导航