A form says the ID number is invalid and you are certain you typed it correctly, or you are writing validation code and want to know which layer to trust. Both cases come back to that one check digit: it is computed from the first 17 digits, and the X at the end is just the result of the same algorithm. The whole chain is three steps: weight, sum, take the remainder and look it up.
The structure of an 18-digit number
The first 6 digits are the address code, the next 8 are the date of birth, then 3 digits of sequence code (the ordering within one area on one day, with the last digit's parity indicating sex), and the final digit is the check digit. The first 17 digits carry all the identity information; the 18th carries none and does one job only: it lets the first 17 be verified arithmetically.
Three steps to the check digit
- Multiply the first 17 digits position by position by the weights 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 and add the 17 products.
- Take that sum modulo 11; the remainder falls between 0 and 10.
- Look the remainder up to get the check digit: 0 to 10 map to 1,0,X,9,8,7,6,5,4,3,2.
Walk a public sample number through it: the first 17 digits 11010519491231002 give a weighted sum of 167, 167 divided by 11 leaves a remainder of 2, the table gives X, and the full number is 11010519491231002X.
| Position | Digit | Weight | Product |
|---|---|---|---|
| 1 | 1 | 7 | 7 |
| 2 | 1 | 9 | 9 |
| 3 | 0 | 10 | 0 |
| 4 | 1 | 5 | 5 |
| 5 | 0 | 8 | 0 |
| 6 | 5 | 4 | 20 |
| 7 | 1 | 2 | 2 |
| 8 | 9 | 1 | 9 |
| 9 | 4 | 6 | 24 |
| 10 | 9 | 3 | 27 |
| 11 | 1 | 7 | 7 |
| 12 | 2 | 9 | 18 |
| 13 | 3 | 10 | 30 |
| 14 | 1 | 5 | 5 |
| 15 | 0 | 8 | 0 |
| 16 | 0 | 4 | 0 |
| 17 | 2 | 2 | 4 |
Adding the 17 products in the right column: 7+9+0+5+0+20+2+9+24+27+7+18+30+5+0+0+4 = 167. The table is also the handiest thing to check against - if your own run does not reach 167, one weight was copied wrong.
The weights are not arbitrary
That string 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 comes from powers of 2 taken modulo 11: the weight of position i, counting from 1, is 2 to the power of (18-i) modulo 11. Working through it position by position matches every value: 2 to the 17th mod 11 is 7, 2 to the 16th is 9, 2 to the 15th is 10, all the way down to 2 to the 1st, which is 2. The lookup step has a derivation too: the check value for remainder r is (12 - r) modulo 11, which for r = 2 gives 10, and 10 can only be written X.
X is not a special marker for anyone
By the formula, the tier with remainder 2 yields a check value of 10. Every position in the number has to be a single character, and 10 takes two, so the Roman numeral X stands in for that slot. An X at the end therefore only means the weighted sum of the first 17 digits happens to be 2 modulo 11; it says nothing about birth date or registration area, and it certainly does not mark a special status.
What it can and cannot catch
Any power of 2 modulo 11 lands between 1 and 10 and is never 0: the remainder sequence is 2,4,8,5,10,9,7,3,6,1 and then back to 2, with a period of 10. Change one digit from d to e and the weighted sum shifts by (e-d) times that position's weight; for the change to go unnoticed the product would have to be a multiple of 11, but |e-d| is at most 9 and no weight is a multiple of 11, so it cannot be done. I enumerated every possible single-character change across the 17 positions: 9 alternative digits each, 153 cases in total, and 0 of them still end with the original check digit X. Escaping a typo is not unlikely; it is impossible.
What it cannot catch is transposition. The weight table repeats with period 10, so position 1 and position 11 share the weight 7, position 2 and position 12 share 9, and so on down to position 7 and position 17 sharing 2 - seven pairs in all. Swap digits between any of those pairs and the weighted sum does not change at all, so the check digit still matches. That is the ceiling shared by every single check digit scheme, not a bug in one implementation.
It also guarantees nothing beyond arithmetic: for a randomly assembled 18-digit string, the chance of hitting the right check digit is one in eleven. Running 200000 random 17-digit prefixes with a fixed seed gave 18063 strings ending in X, or 9.03%, against a theoretical 9.09% - a gap of 0.06 percentage points. In other words it is effective against slips of the hand and nearly useless against fabrication, and it cannot prove that the number belongs to a real person.
Turning a 15-digit number into 18 digits
Expanding the birth date from 6 digits (YYMMDD) to 8 (YYYYMMDD) means prefixing the year with a century digit and appending a check digit. Written without the century, the sample number is 110105491231002; padding 49 to 1949 makes the first 17 digits 11010519491231002, the three steps give X, and the full 18-digit number is 11010519491231002X. The reverse works too: drop the check digit and the century digit and you are back to the 15-digit form. When handling historical data this is the step most easily skipped, because a 15-digit number has no check digit to verify at all.
Layering it in production
Live validation in an input field only needs to go as far as the check digit, which stops typos. Firmer confirmation means a real-name verification channel, and the two layers differ completely in cost and in what they can conclude. In display contexts the number is a sensitive field: a list needs to be recognisable without showing the whole string, which is what Privacy Masking handles. To see the same idea applied to another number type, Bank Card Validator uses a different weighted modulo rule, with different weights but the same structure; and to check this site's weight string digit by digit, Chinese ID Number Checker lists the weighted sum, the remainder and the lookup result together.
Q: Changing one digit is caught, so why not always two
A single-character change alters the weighted sum, and the choice of weights makes it very unlikely to land on the same remainder. Change two digits at once and, if the two deltas cancel out, the sum and the remainder are unchanged and the check digit still matches. That is the ceiling shared by every single check digit scheme, not a bug in one implementation.
Q: Does it ignore the address code and birth date
The check digit only looks at the weighted sum of all 17 digits. It does not judge whether the 6-digit division code really exists, nor whether the date is valid or falls in a leap year. Full format validation usually needs an extra birth-date range check, which is separate logic.
Q: Is a lowercase x acceptable
The rule says X. Most systems tolerate lowercase on input and convert it, but storage and comparison should settle on one form, otherwise the same number ends up as two different records because of letter case.