首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
探索世界的好奇心万岁
Udacity
网易公开课
Godel, Escher, Bach: An Eternal Golden Braid
拉钩
V2EX  ›  分享发现

原来身份证末尾数由算法得出,难怪有尾数 X 的

  •  
  •   jsthon · 2014-12-24 21:26:44 +08:00用 Android 发布 · 7001 次点击
    这是一个创建于 1449 天前的主题,其中的信息可能已经有所发展或是发生改变。
    居民身份证号码,根据〖中华人民共和国国家标准 GB 11643-1999〗中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。 居民身份证是国家法定的证明公民个人身份的有效证件。
      地址码
      (身份证前六位)表示编码对象常住户口所在县(市、旗、区)的行政区划代码。
      生日期码
      (身份证第七位到第十四位)表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。例如:1981年05月11日就用19810511表示。
      顺序码
      (身份证第十五位到十七位)为同一地址码所标识的区域范围内,对同年、月、日出生的人员编定的顺序号。其中第十七位奇数分给男性,偶数分给女性。
      校验码
      (身份证最后一位)是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。作为尾号的校验码,是由号码编制单位按统一的公式计算出来的,如果某人的尾号是0-9,都不会出现X,但如果尾号是10,那么就得用X来代替,因为如果用10做尾号,那么此人的身份证就变成了19位,而19位的号码违反了国家标准,并且我国的计算机应用系统也不承认19位的身份证号码。Ⅹ是罗马数字的10,用X来代替10,可以保证公民的身份证符合国家标准。


    尾数叫校验码,是用前17位用以下公式计算出来的:
    校验码
    (1)十七位数字本体码加权求和公式
    S = Ai * Wi, i = 2, ... , 18
    Y = mod(S, 11)
    i: 表示号码字符从右至左包括校验码字符在内的位置序号
    Ai:表示第i位置上的身份证号码字符值
    Wi:表示第i位置上的加权因子
    i: 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
    Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 1
    (2)校验码字符值的计算
    Y: 0 1 2 3 4 5 6 7 8 9 10
    其中:为保证身份证为18位,故把10改用罗马数字X表示。所以说,你的身份证号尾数为X,表示你的身份证号前17位通过计算,结果为10。


    查阅了相关资料才知道,

    又长知识了。
    35 回复  |  直到 2014-12-25 15:16:29 +08:00
        1
    jsthon   2014-12-24 21:42:00 +08:00 via Android
    程序代码实例

        2
    wzxjohn   2014-12-24 21:54:27 +08:00
    是楼主年龄太小还是我年龄太大。。。N年前用多种方法实现过这个。。。最蛋疼的是帮老师用Excel实现。。。

    PS:我记得似乎高中数学会说一下这个。。。不知道是不是我们这边课本的个别现象。。。
        3
    zhengkai   2014-12-24 22:06:36 +08:00
    https://soulogic.com/archives/364 n年前的困惑

    楼主你想过没有,“由算法得出”跟“结尾有X”没有任何必然联系

    X 的原因只不过他的算法最后一步是 mod 11,但为什么是 11 呢?如果 mod 10,或者 mod 100(这样有两个校验位)就完全没这个问题,匪夷所思
        4
    laobubu   2014-12-24 22:10:19 +08:00
    昨天翻老帖子的时候还遇到过这么一篇:

    http://www.v2ex.com/t/47712

    其中有一个真是碉堡了
    ```python
    get_id = lambda s:s+str((1-2*int(s, 13)) % 11).replace('10', 'X')
    ```
        5
    jsthon   2014-12-24 22:28:40 +08:00 via Android
    @wzxjohn 我是头一次听说这个,周围同学也没听过。嘿嘿


    @zhengkai 我的意思是尾数X不是随机的呀,是因为通过算法得出数字“10”,才用“X”表示的。
        6
    luikore   2014-12-24 22:36:31 +08:00   ♥ 1
    其实逻辑很简单... 看 ruby 的实现:

        7
    mind3x   2014-12-24 22:37:41 +08:00 via Android
    @zhengkai 因为11是最接近10的质数
        8
    iyaozhen   2014-12-24 22:46:27 +08:00
    涨姿势了,我一直以为x是那个县当天出生的人数太多,就用x表示了。
        9
    yaoye0o   2014-12-24 22:52:25 +08:00 via Android   ♥ 1
    一直以为十五位到十八位是按顺序排的四位数,虽然偶尔也会想想“0”和“X”的问题。可我作为male第十七位是“2”是怎么回事😒
        10
    wolfan   2014-12-24 22:53:41 +08:00
    好像用算法得出的身份证应该是从第三代开始的吧。
        11
    zhengkai   2014-12-24 23:44:05 +08:00
    @mind3x 你能告诉我质数在这里的用途么?这里的取模的目的只是个超短的 CRC(循环冗余校验)而已的
        12
    ffffwh   2014-12-24 23:55:42 +08:00
    @mind3x
    同求质数用途

    @yaoye0o
    围观
        13
    jybox   2014-12-25 00:01:03 +08:00
        14
    SharkIng   2014-12-25 00:37:58 +08:00 via Android
    你才知道啊
        15
    ligyxy   2014-12-25 01:01:08 +08:00   ♥ 2
    因为是质数,所以不会出现有仅一位出错而校验位不变的情况
        16
    Quaintjade   2014-12-25 01:20:09 +08:00 via Android   ♥ 1
    关于身份证的几种算法解释及比较参见:
    http://ycool.com/post/9quymdc

    LZ贴的是国标规范,那算法是为极小内存的设备设计的。如果是电脑/手机程序,则没必要用那算法。
        17
    chigco   2014-12-25 02:27:24 +08:00 via Android
    才知道。。
        18
    ericls   2014-12-25 03:37:57 +08:00 via Android
    很久很久以前 就有升位计算器了。。

    还有大陆生份证自动生成器
        19
    Showfom   2014-12-25 03:56:56 +08:00 via iPhone
    再来科普个 电话区号的最后一位是没有0的 0代表10

    所以 0570 是衢州 0571 是杭州 1最大 10最小

    020 广州 021 上海 其实当初的顺序是上海最大 广州最小
        20
    xdlailai   2014-12-25 08:45:45 +08:00
    我是x~~早就科普了下
        21
    rockpine   2014-12-25 08:58:04 +08:00
    入公司后的一个培训检测,就是用python实现这个算法的,那也是我第一次知道最后一位是算出来的
        22
    wildplant   2014-12-25 09:13:37 +08:00 via Android
    关于顺序码,会不会有不够用的情况?比如一个地方一天的出生数量多于999?
        23
    mind3x   2014-12-25 09:20:49 +08:00 via Android
    @zhengkai @ffffwh 机械工业出版社翻译出版的《算法导论》第二版第138页11.3.1节“除法散列法”。为了减小冲突,一般选择“与2的整数幂不太接近的质数”,考虑到身份证其他各位又都用0-9表示,11是无奈之中最好的选择了。
        24
    66beta   2014-12-25 09:29:33 +08:00
    昨天用一个沈粉蒸生成器,发现倒数4位有玄机,前2位会决定性别
        25
    tanyuxiang   2014-12-25 09:38:04 +08:00
    @Showfom 0750前面这个0呢? 好像应该是570,第一个0代表长途。
        26
    plprapper   2014-12-25 10:08:54 +08:00
    记得一个朋友 面试的时候被问道这个问题
        27
    zts1993   2014-12-25 11:26:02 +08:00
    @wildplant 一个区县一天出999个新生儿有点不科学。。。。。
        28
    ahu   2014-12-25 12:21:17 +08:00
    @zhengkai 哇,原来你也混这......


    多年关注,这还是昨天清理书签之后,依然坚决的保留了,虽然好久不更新了.......
        29
    zhengkai   2014-12-25 12:28:11 +08:00
    @Quaintjade 我爱死你了,真的。疑惑了 5 年多的问题终于知道答案了,而且答案出乎我意料确实很牛逼

    另外等价的 PHP 表达是(需要有 GMP 扩展,这还是刚问的,我之前都没用过这扩展)

    return (int)substr($id, -1) == gmp_mod(1 - base_convert($id, 13, 10) * 2, 11);
        30
    zhengkai   2014-12-25 12:31:25 +08:00
    @ahu (⊙o⊙) 可以再留个把月,我最近正准备翻新……比方说,上周我刚研究了一下 bootstrap ……就为了网站改版能适应各种设备,这样才有写东西的好心情
        31
    zhengkai   2014-12-25 13:03:12 +08:00
    @ligyxy 似乎有点明白了,这个等有时间再细想一下,应该是奇数就可以?

    我只考虑了人在键盘上输错的场景,但没考虑数字信号的问题,比方说 8 可能错按成 5(键盘的数字区),但是二者的二进制是 1000 和 0101,连平均值 1/2 都凑不到,所以在校验上远比我想象的 1/10 1/11 的区别要大啊,赞,到底是科班出身,比我这种泥腿子有先天优势
        32
    janxin   2014-12-25 13:36:47 +08:00
    如果我没记错,除了身份证,银行卡也能验
        33
    ligyxy   2014-12-25 14:18:03 +08:00
    @zhengkai

    没看懂你的例子。这个数要满足的要求是与前面所有可能的数互质,例子是:为方便说明前面的数根先据权重变成顺序排列。假设这个数是9,那么前面的数只要最后一位+9,校验码就不变。同理1到10都不能作为这个数。所以区别并非1/10和1/11,而是0和1/17,因为小于11的话连错一位都检验不出来。
        34
    zhengkai   2014-12-25 14:40:29 +08:00
    @ligyxy 差不多就是那个意思,就是错一位跟错一个字节的差别,所以我说还没想明白,得细想嘛,好在上周开始有同事做 RSA 的分享,学习下基础知识,刚讲到中国剩余定理
        35
    ahu   2014-12-25 15:16:29 +08:00
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3686 人在线   最高记录 4019   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.1 · 67ms · UTC 03:27 · PVG 11:27 · LAX 19:27 · JFK 22:27
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1