北京小汽车摇号系统解析(上)

想法 · 13 天前

北京的汽车摇号一直是大批人关注的焦点,我也是参加了N年久摇不中的人之一。之前听了一个传言,号称你摇号编码决定了你多久能够摇中,但具体是哪位的哪个数?又有多种说法,有倒数第几位是多少时永远摇不中的,有第几位是多少时能够前几次肯定能中的,而且还有人现身说法说自己只摇了没几次就中了,就是因为自己的编号符合某个规律。那实际情况是什么样呢?

根据北京摇号当前公布出来的规则:《申请小客车指标办事说明(个人)》

我们来简单过一下摇号过程:

  1. 我们在申请时会分配摇号编码,前4位为随机数,后9位为申请时间戳
  2. 每次摇号前把所有通过审核的摇号人按摇号编码从小到大顺序排列,根据参与摇号次数不同,可能会有1倍概率,2倍概率...N倍概率情况,把从小到大的的编码先排一遍,然后去掉1倍概率的人,把省下的人接着再往下排一遍,然后去掉2倍概率的人...依次类推,我们就得到了所有这次要参加摇号的人的列表
  3. 摇号前一天选出10个人参加摇号当天的种子号摇号
  4. 摇号当天那10个人通过摇号机选出摇号代表,摇号代表通过摇号机摇出6位数的种子数
  5. 用这个种子数随机出1-N(摇号人数)范围的X(摇号量)个数,这个数就代表了第2步生成的列表的序号对应的人中签

这个过程有一些有意思的点和问题需要解答下:

  1. 分配的号码说明说明传言的倒数第几位要求是什么还不是很离谱,如果说是第5位必须是2才能摇中那就太蠢了
  2. 结合《关于公布北京市小客车指标摇号程序的通告》,如果流程没有调整,种子数应该是10个人里选6个,每人摇出一位数
  3. 同样通过《关于公布北京市小客车指标摇号程序的通告》可以知道,之前是有摇号程序可以下载的,而我记得当年我还下载过,但因为当前没有windows电脑,所以没能运行起来。虽然现在官方已经把下载关掉了,但我还能想起来它是个C#写的.net程序

通过上面这些流程,可以保证摇号本身的随机性、公平性,而且还有可解释性,确实是比较好的方式

我们就用24年6月底的摇号结果来复现下,不过现在没有了摇号的原始数据,所以只能复现出随机号码,代码非常简单:

using System;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Random random = new Random(463140);//463140为24年6月的种子
            for (int i = 0;i<9600;i++) {//需要摇出9600个号
                int n = random.Next(1,52020082);//一共有5000多万的顺序码,从1开始到52020081,为什么不从0开始?因为从0开始与摇号结果不匹配,所以原始程序应该是从1开始的
                Console.WriteLine(n);
            }
        }
    }
}

这时输出可以看出是和原数据匹配的

image-20240902115804232.png

直到第925位,我们发现号码不匹配了

image-20240902115843970.png

但是925的结果与我们随机结果的926匹配,说明,925的48346992这个人之前已经摇中过了,也就是说这一次摇号中他中了两次,另外说明程序的逻辑是如果出现多次摇中的情况,那会直接跳过,所以程序并不是严格摇出9600个随机数,而是直到不重复的编码达到9600个才停止。我们剔除掉这个号码后继续比对,最后根据最终数据,这次有53个号是指向前面已经中签的编码,而这9600个随机数也没有重复数字,也就是最多有53组人这次摇中了两次。

乍一听有人一下子摇中两次,是不是有猫腻?根据北京摇号家庭积分计算方式来看,家庭倍数可能达到100+,家庭编码摇中一次概率可能是1%,个人是0.01%,那家庭的摇中两次实际和个人一次概率是相同的,所以也不算稀奇。

至此我们就能够复现整个摇号过程,虽然摇号算法人为干涉不了,但像《三体》里一样,规律也可以是武器,有没有什么规律漏洞能被利用呢?下一次就来看一下这个地方有没有什么漏洞,是不是真的什么隐含的规律在里面

Theme Jasmine by Kent Liao Modified by eLangX