一篇文章带你搞懂mod 11-2算法

阅前提示:本文章仅供研究学习使用(经测试,本文章暂无法正常阅读。)1

引语:mod 11-2算法目前广泛运用于各类加密场景,包括但不限于身份证最后一位的计算等。本文以身份证最后一位数字(校验码)的计算为例子,简单讲解mod 11-2算法。2

我国公民身份号码由十八位数字组成,大致可分割为以下几个部分3

出生地省区代码 出生地城市代码 出生地县区代码 出生日期(年) 出生日期(月) 出生日期(日) 顺序码 校验码
44 09 02 1990 07 24 153 1
广东省 茂名市 茂南区 (奇数表男性,偶数表女性)

那这个“1”是怎么来的呢?先看下面一组国标规定的加权因子4

7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

这个因子的计算方法2
$$
2^{18-i} \bigoplus 11
$$
其中,i为各个号码的位数。

这组因子通常是固定的,我们可以直接利用它来计算。

身份号码前十七位分别对应这组因子的每一个数字,我们先做对应相乘。以上面表格的号码为例,将每一位数字分别与其对应的加权因子相乘,

例如:
$$
4×7,4×9,0×10,9×5...
$$
得到数字:
$$
a_1,a_2,a_3,a_4...(a_1 = 28,a_2 = 36 ...)
$$
求和,得到数字b = 319

我们再将该数字套用到这样一个公式里2
$$
(12-(b\bigoplus11))\bigoplus11
$$
最后算出来的数字即为校验码。

计算过程如下2
$$
\because b = 319,\
\therefore b \bigoplus 11 = 319÷11的余数 = 0 \
\therefore 12 - 0 = 12 \
\therefore 12÷11的余数 = 1 \
\therefore 校验码为1
$$
用一个函数写下来就是2
$$
m = (12-(\sum_{n=1}^{a_{17}}a_n \bigoplus 11))\bigoplus 11
$$
其中:a为每位原数字分别乘加权因子后的结果,m最终为校验码,n为每位数字的位数。

用这个算法算出来的校验码,取值范围为0~10,其中10使用罗马数字“X”来表示。

基于本算法制作的身份号码校验码推算程序(源代码)5

#include <bits/stdc++.h>
using namespace std;
int main(){
	int a[20] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
	int b[20],c;
	for(int i = 0; i < 17; i++){
		cin >> b[i];
	}
	for(int i = 0; i < 17; i++){
		c += a[i] * b[i];
	}
	cout << (12-(c%11))%11;
    return 0;
}
import os
a = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]
b = list(input())
c = 0
for i in range(0,17):
    c += a[i] * int(b[i])
def mod(x):
    return (12-(c%11))%11
print(mod(c))
os.system("pause")
indo:{
    int list a[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]
    int b,c
    l = input(b.list)
    range(0,17):{
		c += a[RANGE_I] * b[RANGE_I]
    }
    public void mod(x):{
    	return (12-(c%11))%11
    }
    output(mod(c))
}

Footnotes

  1. 本文编写依据:ISO 7064:1983

  2. 由于编辑器限制,本文全文以⊕符号表取余,即取两数相除的余数 2 3 4 5

  3. 信息来源:全国标准信息公共服务平台

  4. 数据来源:自己算的(

  5. 程序代码由本人临时编写,所以代码尚未规范