チェックディジットとは?モジュラス10・モジュラス11の計算方法と検出できない誤り

「チェックディジットとは何?」「チェックディジットはどのように計算するの?」「バーコードやクレジットカード番号にも使われている?」と疑問に感じている方も多いのではないでしょうか。

チェックディジットは、入力された数字やコードに誤りがないかを確認するために付加される数字です。

商品バーコード、ISBN、銀行口座番号、クレジットカード番号など、さまざまな場面で利用されています。

この記事では、チェックディジットの意味から仕組み、計算方法、具体例、利用される場面まで、初心者にもわかりやすく解説します。

チェックディジットとは?

チェックディジット(Check Digit)とは、番号やコードの入力・読み取りミスを検出するために、コードの末尾などに付加される数字のことです。

日本語では「検査数字」などと呼ばれます。

たとえば、ある番号が次のようになっているとします。

12345678

この番号に一定のルールで計算した数字を追加して、次のようなコードにします。

123456789

この場合、最後の「9」を使って元の番号に誤りがないかを確認できます。

重要なのは、チェックディジットそのものが情報を増やすための数字ではなく、「番号が正しい形式になっているか」を検査するための数字だということです。

チェックディジットは何のためにある?

チェックディジットの主な目的は、入力ミスや読み取りミスなどのエラーを検出することです。

たとえば、商品のバーコードを読み取る場合、数字が正しく読み取られているとは限りません。

また、ユーザーが会員番号や口座番号を手入力すると、数字を1桁間違える可能性があります。

そこでチェックディジットを利用すると、次のようなエラーを検出できます。

  • 数字の入力ミス
  • バーコードの読み取りミス
  • 転記ミス
  • 一部の数字の入れ替わり

つまりチェックディジットは、データの「入力ミスを見つける仕組み」として利用されています。

チェックディジットの仕組み

チェックディジットの基本的な考え方はシンプルです。

1. 元となる数字を用意する

たとえば、次の数字があるとします。

1 2 3 4 5

2. 決められた計算方法で計算する

それぞれの数字に重みを掛けたり、合計したりして計算します。

3. チェック用の数字を求める

計算結果から、条件を満たす数字を求めます。

4. 元の番号に追加する

たとえばチェックディジットが「6」だった場合、次のようなコードになります。

123456

5. 利用時に再計算する

入力された番号から再び計算を行い、最後のチェックディジットと一致するか確認します。

一致すれば、

「計算上は正しい可能性が高い」

と判断できます。

一致しなければ、

「入力または読み取りに何らかのエラーがある可能性がある」

と判断できます。

チェックディジットの計算方法

チェックディジットには複数の計算方式があります。

代表的なものには、次のようなものがあります。

  • モジュラス10
  • モジュラス11
  • Luhnアルゴリズム
  • ISBNのチェックディジット
  • JANコードのチェックディジット

それぞれ計算方法が異なります。

モジュラス10とは?

モジュラス10(Modulus 10)は、チェックディジットの代表的な計算方法です。

数字に一定の重みを掛けて合計し、その合計を10で割った余りなどを利用してチェックディジットを求めます。

たとえば、次の数字について考えてみます。

1 2 3 4 5 6

それぞれの数字に重みを設定します。

数字: 1 2 3 4 5 6
重み: 2 1 2 1 2 1

このように重みを掛けて計算します。

1×2
2×1
3×2
4×1
5×2
6×1

ただし、実際のモジュラス10には複数のバリエーションがあるため、どの規格で計算するかによって具体的な手順は異なります。

Luhnアルゴリズムとは?

Luhnアルゴリズムは、クレジットカード番号などの検証に使われる代表的なチェック方式です。

「モジュラス10アルゴリズム」と呼ばれることもあります。

基本的には、数字を一定のルールで処理して合計し、合計値が10の倍数になるようにチェックディジットを設定します。

たとえば、次の番号について考えます。

7992739871

この番号からチェックディジットを計算すると、

3

となり、

79927398713

という番号になります。

検証するときは、この番号全体について同じルールで計算し、条件を満たしているかを確認します。

Luhnアルゴリズムの特徴

  • 計算が比較的簡単
  • 1桁の入力ミスを検出できる
  • 一部の桁の入れ替えを検出できる
  • コンピューターで簡単に実装できる

ただし、チェックディジットは暗号化ではありません。

正しい番号であることを確認するための仕組みであり、不正利用や情報漏えいを防止するためのセキュリティ機能とは異なります。

モジュラス11とは

モジュラス10が10で割った余りを使うのに対して、モジュラス11は11で割った余りを使います。銀行の口座番号や社内の管理番号などで使われてきた方式です。

計算の手順(ウェイト2〜7)

  • 各桁に右から順に 2, 3, 4, 5, 6, 7 の重みをかける(7の次は再び2に戻る)
  • かけた結果をすべて足す
  • 合計を11で割った余りを求める
  • 11 から余りを引く
  • 結果が10以上なら検査数字は0にする
def mod11w2to7(body):
    """モジュラス11 ウェイト2〜7"""
    ws = [2, 3, 4, 5, 6, 7]
    s = sum(int(c) * ws[i % 6] for i, c in enumerate(reversed(body)))
    r = 11 - s % 11
    return 0 if r >= 10 else r

for b in ["12345", "987654", "1111111"]:
    print("%-8s -> 検査数字 %d" % (b, mod11w2to7(b)))

実行結果:

12345    -> 検査数字 5
987654   -> 検査数字 5
1111111  -> 検査数字 4

重みの付け方は決まりが1つではありません。「ウェイト2〜7」のほかに「ウェイト2〜10」や、左から重みを付ける流儀もあります。既存のシステムに合わせるときは、必ずその仕様書で重みと余りの扱いを確認してください。同じ「モジュラス11」という名前でも結果は変わります。

モジュラス10との違い

モジュラス10 モジュラス11
割る数 10 11
検査数字 必ず0〜9に収まる 11になる場合があり、0に置き換える処理が必要
隣接した入れ替え 差が5の組を見逃す 重みがすべて違うので入れ替えに強い
主な用途 JANコード、クレジットカード 銀行口座、社内の管理番号

モジュラス11は桁ごとの重みがすべて違うため、順番を入れ替える誤りに強いという利点があります。一方で検査数字が11になる場合の扱いを決めなければならず、その流儀が組織ごとに違うことが使いにくさにつながっています。

マイナンバーの検査用数字

マイナンバー(個人番号)は12桁で、最後の1桁が検査用数字です。前の11桁から計算されます。

考え方はモジュラス11に近く、余りが0か1のときは検査用数字を0にするという決まりがあります。

def mynumber_digit(d11):
    """マイナンバーの検査用数字(前の11桁から計算)"""
    s = sum(int(c) * (i + 2 if i < 6 else i - 4)
            for i, c in enumerate(reversed(d11)))
    r = s % 11
    return 0 if r <= 1 else 11 - r

for b in ["12345678901", "00000000000", "98765432109"]:
    print("%s -> 検査用数字 %d" % (b, mynumber_digit(b)))

実行結果:

12345678901 -> 検査用数字 8
00000000000 -> 検査用数字 0
98765432109 -> 検査用数字 3

この計算で分かるのは「桁の並びとして成立しているか」だけです。実際に存在する番号かどうかは判定できません。入力フォームでの打ち間違い検出には使えますが、本人確認の代わりにはなりません。

なお、マイナンバーは法律で収集・保管できる場面が限られています。検査用数字の計算ができることと、番号を保持してよいことは別の話です。

JANコードにもチェックディジットが使われている

身近な例として、JANコード(Japanese Article Number)があります。

スーパーやコンビニなどの商品についているバーコードを思い浮かべるとわかりやすいでしょう。

JANコードのバーコード
商品に付けられているJANコードのイメージ

日本で一般的に利用されるJANコードには、13桁の「JAN-13」などがあります。

JAN-13では、最後の1桁がチェックディジットです。

XXXXXXXXXXXXX
            ↑
      チェックディジット

つまり、最初の12桁を使って計算し、13桁目のチェックディジットを求めます。

JANコードのチェックディジットの計算方法

JAN-13では、最初の12桁を使ってチェックディジットを計算します。

たとえば、次の12桁があるとします。

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

奇数番目と偶数番目の数字に異なる重みを設定して計算します。

基本的には、

奇数位置:そのまま
偶数位置:3倍

として合計します。

その合計値を10で割った余りを利用して、チェックディジットを求めます。

計算式のイメージは次のとおりです。

チェックディジット
=(10 − 合計値 mod 10)mod 10

このようにして求めた数字を13桁目に追加します。

ISBNにもチェックディジットがある

本の識別番号であるISBNにもチェックディジットが使われています。

ISBN-13の番号とバーコード
本に記載されているISBNのイメージ

現在一般的に使われているISBN-13では、13桁目がチェックディジットです。

たとえば、

978XXXXXXXXX?

という番号があった場合、最後の「?」がチェックディジットになります。

ISBN-13では、各桁に「1」または「3」の重みを掛けて計算します。

概念的には、次のようになります。

1 × 1
2 × 3
3 × 1
4 × 3
5 × 1
6 × 3
...

そして、合計値から最後のチェックディジットを求めます。

クレジットカード番号にもチェックディジットが使われる

クレジットカード番号にも、Luhnアルゴリズムによるチェックが広く利用されています。

カード番号を入力した際に、

  • 数字の桁数が明らかにおかしい
  • チェックディジットの計算結果が合わない

といった場合、入力された番号が正しくない可能性があります。

ただし、チェックディジットが正しいからといって、

「実際に存在するカードである」

ことや、

「決済できるカードである」

ことを保証するわけではありません。

あくまで番号の形式・整合性を確認するための仕組みです。

チェックディジットで検出できるエラー

チェックディジットは、すべてのエラーを検出できるわけではありません。

しかし、代表的な入力ミスを検出するのに役立ちます。

1桁の数字を間違えた場合

たとえば、

123456

を

123457

と入力してしまった場合です。

チェックディジットを使えば、このようなエラーを検出できる場合があります。

数字の順番を間違えた場合

たとえば、

123456

を

123546

のように入力したケースです。

使用するアルゴリズムによっては、このような隣接する数字の入れ替えを検出できます。

桁を抜かした場合

123456

を

12346

のように1桁抜かしてしまった場合も、方式によっては検出できます。

ただし、検出できるエラーの種類や範囲はアルゴリズムによって異なります。

チェックディジットで検出できないこと

チェックディジットには限界があります。

たとえば、入力ミスによって別の数字になったにもかかわらず、たまたまチェックディジットの条件を満たしてしまう場合があります。

そのため、

チェックディジットが正しい=データが100%正しい

とは限りません。

チェックディジットはあくまで、「よくある入力・転記・読み取りミスを効率的に検出する仕組み」と考えるとよいでしょう。

どんな誤りを捕まえられるのか(実測)

「1桁の打ち間違いは検出できる」と説明されますが、実際に全パターンを試して確かめました。JANコードと同じモジュラス10ウェイト3を使います。

1桁の打ち間違いは全部捕まる

def cd(d12):
    s = sum(int(c) * (3 if i % 2 else 1) for i, c in enumerate(d12))
    return (10 - s % 10) % 10

base = "490177701868"
full = base + str(cd(base))          # 4901777018686

ng = 0
for i in range(13):
    for d in "0123456789":
        if d == full[i]:
            continue
        cand = full[:i] + d + full[i+1:]
        if cd(cand[:12]) == int(cand[12]):
            ng += 1
print("1桁だけ変えた %d 通りのうち、検査を通ってしまうもの: %d" % (13 * 9, ng))

実行結果:

1桁だけ変えた 117 通りのうち、検査を通ってしまうもの: 0

117通りすべてで検出できました。1桁の打ち間違いは必ず捕まります。

隣り合う2桁の入れ替えは、差が5のとき見逃す

ここが重要です。隣り合う数字を入れ替える誤り(転置)は、差が5の組だけすり抜けます。

import random
random.seed(1)

bad = 0
for _ in range(5000):
    d = [random.choice("0123456789") for _ in range(12)]
    i = random.randrange(0, 11)
    a = random.randrange(0, 5)
    d[i], d[i+1] = str(a), str(a + 5)      # 差が5の組を置く
    full = "".join(d) + str(cd("".join(d)))
    c = list(full)
    c[i], c[i+1] = c[i+1], c[i]            # 入れ替える
    c = "".join(c)
    if cd(c[:12]) == int(c[12]):
        bad += 1
print("差が5の入れ替え 5000通り → 検査を通ってしまった:", bad)

実行結果:

差が5の入れ替え 5000通り → 検査を通ってしまった: 5000

5,000通りすべて見逃しました。理由は計算で説明できます。

隣り合う2桁は重みが1と3(または3と1)なので、a と b を入れ替えると合計の変化は (3a + b) - (a + 3b) = 2(a - b) です。これが10の倍数になると検査を通ってしまいます。

入れ替える2桁 2(a - b) 10で割った余り 検出
1 と 6 -10 0 見逃す
2 と 7 -10 0 見逃す
0 と 5 -10 0 見逃す
4 と 9 -10 0 見逃す
1 と 2 -2 8 捕まる

a - b が5の倍数、つまり差がちょうど5のときだけ余りが0になります。43,000通り以上の入れ替えを試しても、見逃しが起きたのは差が5の組だけでした。

重みがすべて違うモジュラス11はこの弱点を持ちません。人間が番号を手で入力する場面で入れ替えの誤りが多いなら、モジュラス11のほうが向いています。

チェックディジットとチェックサムの違い

「チェックディジット」と似た言葉にチェックサムがあります。

どちらもデータの誤りを検出するために使われますが、厳密には意味が異なります。

項目 チェックディジット チェックサム
主な対象 数字・コード データ全般
付加される値 1桁など 複数桁になることもある
目的 入力・転記ミスの検出 データ破損などの検出
代表例 JAN、ISBN ファイル、通信データなど

チェックディジットは、番号やコードの検証に特化した仕組みと考えると理解しやすいでしょう。

チェックディジットとハッシュ値の違い

チェックディジットとハッシュ値も混同されやすい言葉です。

しかし、目的が大きく異なります。

チェックディジット

主に、

「番号の入力ミスがないか?」

を確認するために利用します。

ハッシュ値

主に、

「データが変更されていないか?」

を確認したり、データを効率的に識別したりするために利用します。

また、暗号学的ハッシュ関数では、セキュリティ用途にも利用されます。

したがって、

  • チェックディジット=簡易的な誤り検出
  • ハッシュ値=データの識別・完全性確認など

と覚えておくとよいでしょう。

Pythonでチェックディジットを計算する

チェックディジットの計算は、Pythonでも簡単に実装できます。

たとえば、Luhnアルゴリズムによる検証処理の例です。

def check_luhn(number):
    digits = [int(x) for x in str(number)]

    total = 0
    parity = len(digits) % 2

    for i, digit in enumerate(digits):
        if i % 2 == parity:
            digit *= 2

            if digit > 9:
                digit -= 9

        total += digit

    return total % 10 == 0


print(check_luhn("79927398713"))

実行すると、次のようになります。

True

これは、指定した番号がLuhnアルゴリズム上の条件を満たしていることを意味します。

プログラミングでチェックディジットを利用するメリット

システム開発では、ユーザーが入力した番号をそのままデータベースに登録するのではなく、チェックディジットを使って事前に検証することがあります。

たとえば、次のような番号です。

  • 会員番号
  • 商品コード
  • 伝票番号
  • 請求書番号
  • 銀行口座番号
  • ISBN
  • バーコード番号

入力時にチェックすることで、データの入力ミスを早期に発見できます。

チェックディジットを使うメリット

入力ミスを検出できる

人間が数字を入力すると、どうしても入力ミスが発生します。

チェックディジットを利用すれば、一定のミスを自動的に検出できます。

実装が比較的簡単

チェックディジットは複雑な暗号技術を必要としない方式も多く、プログラムで簡単に実装できます。

データの信頼性を高められる

商品コードや会員番号などの入力時に検証を行うことで、間違ったデータがシステムに登録されるリスクを減らせます。

チェックディジットのデメリット

一方で、チェックディジットにも限界があります。

すべてのエラーを検出できるわけではない

アルゴリズムによって検出できるエラーが異なります。

セキュリティ対策ではない

チェックディジットは、番号の正当性を簡易的に確認する仕組みです。

そのため、次のような問題を防ぐものではありません。

  • 不正アクセス
  • なりすまし
  • データ盗難
  • パスワード攻撃

アルゴリズムによって性能が異なる

どのチェックディジット方式を採用するかによって、検出できるエラーの種類が変わります。

チェックディジットは身近なところで使われている

チェックディジットは、普段意識することは少ないものの、さまざまな場所で利用されています。

利用例 チェック方式など
JANコード モジュラス10系
ISBN-13 モジュラス10系
クレジットカード番号 Luhnアルゴリズム
商品コード 規格による
口座・識別番号 規格による
バーコード 規格による

このように、「数字を間違えて入力すると困る」場面で活躍している技術です。

関連記事

あわせて読むと理解が深まります。

あわせて読みたい

「情報I」の出題は分野をまたいで関連づけて問われるのが特徴です。あわせて四分位数とは?計算方法から活用例まで、スマートコントラクトとは?仕組みから活用例まで初心者向けに、二分探索とは?アルゴリズムの仕組みから計算量・活用例まで分かりやすく解説も参考になります。

共通テストの出題範囲と勉強法は【情報Ⅰ】コンピュータとプログラミングの対策にまとめています。

まとめ:チェックディジットとは入力ミスを検出するための数字

チェックディジットとは、数字やコードに誤りがないかを確認するために付加される数字です。

ポイントをまとめると、次のとおりです。

  • チェックディジットは「検査数字」とも呼ばれる
  • 数字やコードの入力ミス・転記ミスなどを検出する
  • JANコードやISBNなどで利用されている
  • クレジットカード番号ではLuhnアルゴリズムが利用される
  • 計算方法には複数の規格がある
  • チェックディジットが正しくてもデータの完全性を保証するものではない
  • 暗号化やセキュリティ対策とは異なる
  • Pythonなどのプログラミング言語でも簡単に実装できる

プログラミングを学ぶ際には、チェックディジットの計算を実際にコード化してみることで、「アルゴリズム」「繰り返し処理」「剰余演算」「条件分岐」などの基本をまとめて学習できます。

特にPythonでは比較的少ないコードで実装できるため、プログラミング初心者のアルゴリズム学習にも適した題材です。