Check digit algorithms look like a long list of unrelated recipes until you notice that they are variations on a single idea. Every one of them takes the characters that precede the final position, gives each of them a weight, adds the results together, divides by a modulus and turns what is left over into the closing character.
Once that skeleton is visible, choosing between the mod-10, mod-11 and mod-97 families stops being a matter of taste and becomes a matter of matching four parameters to the job. This article compares the families at that level and leaves the arithmetic of any single card scheme to the guides that own it.
What are the main families of check digit algorithms?
The customary division is by modulus, because the modulus is the parameter that shapes everything else.
The mod-10 family divides the weighted sum by ten, so the remainder is always a single decimal digit and needs no further translation. The mod-11 family divides by eleven, which produces eleven possible remainders; ten of them fit a single digit and the eleventh has to be represented some other way. The mod-97 family divides by ninety-seven, and is usually reached for when the identifiers are long or contain letters.
ISO 7064 is the international standard that gathers several published check-character systems of this kind, including the MOD 97-10 arrangement used for account identifiers that cross borders. Naming a family tells you the shape of the arithmetic, not the exact parameters a particular scheme settled on — a distinction that matters as soon as you place these routines inside a validation pipeline that also has to check character sets and lengths.
How mod-10, mod-11 and mod-97 differ
The differences that matter in practice are all consequences of the modulus.
| Family | Modulus | Typical use | The awkward part |
|---|---|---|---|
| mod-10 | 10 | Short numeric identifiers, card numbers and similar schemes | Its weights are symmetric in some arrangements, which weakens transposition detection |
| mod-11 | 11 | Identifiers where the designers wanted stronger error detection | One remainder value does not fit a single digit and must be mapped or avoided |
| mod-97 | 97 | Long identifiers, especially alphanumeric ones such as cross-border account numbers | Needs letters converted to numbers first, so most implementations rely on a library rather than hand-written code |
A card scheme that closes its numbers with a doubling-and-summing mod-10 routine belongs to the first row. That routine is mod-10 arithmetic wearing a name, and the family view is the useful one here: the same arithmetic appears in loyalty schemes, internal identifiers and several national numbering systems, which is why a helper named after cards tends to misfire elsewhere. The third row is the one behind long cross-border account identifiers, worked through step by step in IBAN structure and mod-97.
Weighting and modulus: the parameters inside a family
Inside one family the members differ in exactly three places. The first is the weight sequence — which positions are multiplied by what, and whether the pattern repeats or grows. The second is the modulus itself, chosen to suit the length and the alphabet of the identifier. The third is the mapping from remainder to check character, which is where most of the visible variety lives.
That mapping is worth a second look, because it is where a scheme has to make a decision about leftovers. A mod-10 remainder is a digit by construction. A mod-11 remainder may be ten, and the scheme must either forbid the combinations that produce it, or shift the result into a different range, or reserve a symbol such as the letter X for it. A mod-97 remainder has to be reduced again into the check characters the scheme actually allows.
Skipping that decision is the most common way a hand-written implementation drifts away from the published rule. The arithmetic will look right on the comfortable inputs and fail on the awkward ones.
Why do some algorithms catch transposition errors?
Adjacent characters get swapped constantly when something is typed by hand, so catching that class of slip is a design goal rather than a bonus.
The mechanism is the weights. When a scheme multiplies each position by a different value, swapping two neighbours changes how much each of them contributes, and the total moves with it. When the weights are symmetric — the same value on both sides of the pair — the two contributions simply trade places and the total is unchanged, so the check waves the swap through.
That is the reason the doubling member of the mod-10 family exists at all. Doubling alternate positions makes each one’s weight depend on where it sits, which restores the ability to notice a swap. It is still not perfect: certain pairings produce the same total before and after, and the accurate way to describe any check digit is that it catches every single-character error and most, not all, adjacent transpositions.
Four questions to ask before choosing an algorithm
Selection is easier when it is treated as a short set of concrete questions rather than a matter of preference.
- How long can the identifier be, and is the length fixed or variable?
- Which characters are legal — digits only, or letters as well?
- Do the expected errors come from people typing, from machines generating, or both?
- What happens when the arithmetic produces a check character that does not fit the format?
The fourth question is the one teams skip. A scheme that can produce a two-digit remainder on a single-digit field needs either a rule for the exceptions or a modulus that avoids them, and discovering that late means rewriting the rule rather than adjusting it.
Two habits follow. Do not invent parameters: implement what the scheme publishes, then prove the implementation against that scheme’s own published material. And when two schemes in one product share most of their arithmetic, share the implementation and let the parameters differ, rather than copying the routine and letting the copies drift apart.
For developers: one implementation for a whole family
The family view pays for itself in the code. A single routine parameterised by weight sequence, modulus and mapping covers every member, and every new scheme becomes a configuration rather than a new file. That keeps review short, because the arithmetic is reviewed once and the parameters are checked line by line.
Two design details prevent most of the pain. Return the computed check character rather than a boolean, so a caller can print what the arithmetic expected; the difference between a wrong value and an unsupported scheme then stays visible all the way up. And keep the remapping step explicit in the configuration, because that is the part that differs between schemes and the part nobody remembers.
Every set of digits used to illustrate this article is synthetic — the parameters described are public knowledge, while the example strings are constructed for demonstration and describe no number that any scheme has issued.
Next steps
List the numbering schemes your product handles and place each one in a family before you write anything else. Then generate a value, alter a single character and alter a pair of neighbours, and confirm that both fail; the number validation tool shows the verdicts a validator should be able to tell apart, the IBAN and mod-97 article is the worked case for the long-identifier family, and how number validation works steps back to the three layers these algorithms sit inside.