zoukankan      html  css  js  c++  java
  • 团购码,你知多少?——线性同余产生随机数

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

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

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

    假设用点击领用团购码,产生一个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依赖的争用问题。

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

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

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

  • 相关阅读:
    递延收益的主要账务处理
    少数股东权益
    一揽子交易中处置价款与净资产账面价值差额为什么计入其他综合收益
    为什么权益法下其他综合收益合并时要计入投资收益
    R语言代写实现MCMC中的Metropolis–Hastings算法与吉布斯采样
    加速R语言代码的策略
    R语言代写:EM算法和高斯混合模型的实现
    R语言代写进行网站评论文本数据挖掘聚类
    R语言代写对推特数据进行文本情感分析
    WEKA代写文本挖掘分析垃圾邮件分类模型
  • 原文地址:https://www.cnblogs.com/zrhai/p/4071023.html
Copyright © 2011-2022 走看看