Vita弟弟上个月去出席了电子学会的中学生机器人技术等级考试,考试的时侯须要在笔记本上输入身份证号码和密码。当然了,参加考试的大部分都是跟他差不多大的女儿,据说有老师帮忙输身份证号码和密码。结束以后我问他,你身份证号码自己背得出吗?他说背不出,就晓得中间有出生年月日,然后最后一位是个X。
然后他突然问,那个X是啥意思啊?爸爸你身份证最后一位是几?我说我和你母亲最后一位都不是X,但是你和你哥哥都是X,哈哈哈。至于哪个X代表哪些,这个问题挺有意思的,需要花点时间才会讲清楚。
我记得我小时候身份证号码还是15位的。1999年,国家出台新标准,把身份证号码升到了18位,其中把出生年份从原先的2位改成了4位,然后又在最后加下来1位。1999年的时侯我在上高中,很多朋友在讨论这个升位的事情,因为有人发觉自己的身份证号升位以后最后一位不是数字而是X,还引起了一波莫名的恐惧。
当时对这个X有各类传闻,有人说表示你这一位不知道是几先待定,听上去挺不靠谱的。而且,在很长一段时间内,这个X确实带来了一些麻烦,因为它不是数字,在好多系统上面输入和储存都出了问题。反正在那种时侯似乎没人给出一个正确的解释,我恐怕很多人到如今也没搞清楚X究竟是如何一回事。
好了,言归正传。
简单来说,身份证号码的最后一位是一个校验码,是通过一组算法,根据上面17位数字估算下来的。这个算法的最后一步(其实不止最后一步)是mod 11(除以11取余数),于是得到的结果就有0~10一共11种。然而,如果得到的结果是10,总不能把身份证号写成19位吧,所以就找了一个字母X来代表10,本来字母X也就是罗马数字的10,没毛病。
本来以为这样解释就差不多了,但是娃有时候没这么好打发。Vita姐姐问,那为何要mod 11呢?如果mod 10的话,就不会出现X了吧。
Hmm。。。灵魂叩问。。。
制定国标的人可没这么傻,用mod 11一定有他的道理,更毕竟,这个算法显然是ISO7064上面规定的,说白了,这是个国际规范,并不是我国自己拍脖子想下来的。
那么ISO7064里规定的这个算法,到底是如何算的呢?《中华人民共和国国家标准GB11643-1999》中给出了一个身份证号码的事例,我们就用这个事例来算一下吧。这个反例的前17位号码是:
号码:1 1 0 1 0 5 1 9 4 9 1 2 3 1 0 0 2
现在我们要拿这17位算出最后一位。首先,每一位都要先减去一个权重。权重显然就是一个整数,每一位的权重是多少,我们要先算下来。
我们假定最右侧一位是第1位,最左侧一位是第17位,那么第N位的权重就是2的N次方再乘以11取余数。
比如说,第1位的权重就是2的1次方,也就是2;第2位就是4;第3位就是8。到了第4位就有点不一样,2的4次方等于16,我们要乘以11取余数,结果应当是5。以此类推,我们就得到了所有位的权重:
号码:1 1 0 1 0 5 1 9 4 9 1 2 3 1 0 0 2
权重:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
接下来我们用每一位的号码与对应的权重相加,然后结果再乘以11取余数,得到加权结果。比如第1位:2x2=4;第2位:0x4=0;但是到了第5位:3x10=30,我们还要取11的余数,结果等于8;以此类推:
号码: 1 1 0 1 0 5 1 9 4 9 1 2 3 1 0 0 2
权重: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
加权结果:7 9 0 5 0 9 2 9 2 5 7 7 8 5 0 0 4
然后,我们将所有的加权结果相乘求和,结果再乘以11取余数:
7 + 9 + 0+ 5+ 0+ 9+ 2+ 9+ 2
+ 5+ 7 + 7 + 8+ 5+ 0+ 0+ 4
= 79mod11 =2
最后一步,我们用12除以里面的结果,得到的数字再乘以11取余数:
12 - 2 = 10 mod 11 = 10
这个结果就是身份证最后一位号码了。如果结果是0~9,那么就直接写上相应的数字,但若果结果是10(比如前面这个反例),那你的身份证最后一位就是X啦。
这里须要说明的一点是,上面这个算法上面有很多减去11取余数(mod 11)的步骤,但似乎按照模运算的性质,只要在最后一步取余数就可以了,我们之所以在上面的步骤也取了余数,只是为了让数字变小,计算上去更简单。
讲到这儿,Vita立即用自己的身份证号码算了一遍:
知道了最后一位的算法,我们还是没办法回答为何要用mod 11这个问题。别急,为了回答这个问题,我们先来看一下这个校验码究竟有什么用。
既然叫校验码,当然是拿来校准身份证号码正确不正确的。
我们平常抄录、填写或则输入身份证号的时侯,很有可能会出错,比如说,把其中一位数弄错了,这种情况下,通过校验码就可以辨识下来,因为任意一位数弄错,算下来的校验码就不一样了。
但是,要实现这个功能,必须满足两个条件:①模数(就是乘以几取余数,比如这儿是11)不能比10小;②模数与权重必须互质。
我们一个一个解释。
①模数不能比10小,为什么呢?假如模数比10小,例如9,那么无论权重是几,我用9减去权重再乘以9余数永远是0(因为除以9得到的数必将被9整除),而用0除以权重再乘以9余数也永远是0,那么假如我把某位数0错写成9,得到的校验码必将是一样的,那不就检测不出错误了吗?换句话说,因为我们每一位都使用了0~9一共10个数字,因此模数起码得是10能够防止出现上述情况。
再看②模数与权重必须互质,为什么呢?假设模数是10,权重是2,2和10不是互质的(因为有公因数2),这样会发生哪些问题呢?很简单,1x2和6x2,除以10得到的余数是相同的,同样地,2x2和7x2也是相同的,那么若果是这种数字相互弄错,校验码也检测不下来了。
看到这儿,你都会发觉11是一个挺好的模数。首先,它是个小于等于10的数;其次,它是一个因数,一个素数与任何大于它的数都互质,因此我随意选1~10中的任何数作为权重都没问题。
除了把某一位数弄错,我们可能还常常犯一种错误,那就是把相邻两位的数字写反。上面的估算过程中我们早已发觉,相邻两位的权重都是不同的,因此假如把相邻两位数字写反,验证码的估算结果都会不同,也就可以检测下来了。
实际上,如果再看一遍权重的次序:
号码:1 1 0 1 0 5 1 9 4 9 1 2 3 1 0 0 2
权重:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
我们可以发觉,权重每隔10位就重复了,而权重相同的两位写反的情况难以被验证码检测下来,但是由于这样的情况要把距离10位的两个数写反就会发生,这种几率太低了。
但是要实现这个功能,权重和模数也必须互质,原因你们可以自己思索,跟里面讲的差不多。那么假定我们用10作为模数,那么与10互质的数只有1、3、7、9这4个,那么我们的权重就只能是1 3 7 9 1 3 7 9 1 3 7 9……也就是说,每隔4位权重就重复了,这样一来,两位数字写反倒难以检测下来的情况就大大降低了。
此外,10上面的质数5也是一个麻烦,因为5和任何权重(奇数)相乘,mod 10以后结果都是5,而0和任何权重相加结果都是0。也就是说,如果有两位数是0和5,无论它们出现在任何位置,写反以后都未能通过模10的验证码检测下来,因为估算结果是不变的。
所以,合数天生不太适宜在这个验证码系统里做模数,残念。
好了,我们总结一下。这个验证码须要实现的功能是:
要满足这样的要求:
11是小于等于10的最小的一个素数,所以用11做模数是最合适的。只不过,用11做模数,最后的估算结果就可能出现10,而身份证的验证码只有一位,这种情况就只得用X来表示啦。
最后给你们留个作业,就是我们题图上的那张韦小宝的身份证:
这张身份证图片时常被好多文章用来做样例来解释身份证编码的构成,但显然,这个身份证号的最后一位校验码是错的,你能算出正确的校验码是多少吗?算下来在下边留言哦,没有奖品,哈哈。