IMEIのチェックデジット、「右から偶数番目を2倍」だと逆になる

  • Algorithm
  • Luhn
  • IMEI

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

IMEI(15桁)の末尾1桁はチェックデジットで、Luhnアルゴリズムで算出される。クレジットカード番号の検証で使われているのと同じ方式。

計算自体は単純だけど、「どの桁を2倍するか」の説明で右からか左からか、奇数番目か偶数番目かがよく食い違う。同じ処理を指しているつもりで逆のことを書いてしまうケースがあるので、そこを整理する。

手順

対象は先頭14桁(チェックデジットを除いた本体部分)。

  1. 14桁を用意する
  2. 右から数えて奇数番目(1番目、3番目、5番目…)の桁を2倍する
    • これはチェックデジットの直前の桁からスタートして1つおき、という意味
  3. 2倍した結果が10以上になったら各桁を足す(12 → 1+2=3)。これは「2倍して9を超えたら9を引く」と等価
  4. 全部の桁を合計してsumを作る
  5. チェックデジット cd = (10 - (sum % 10)) % 10

ここでよくある書き間違いが「右から偶数番目を2倍」という表現。これだと2倍する桁がひとつずれて、算出される値も変わってしまう。「右から奇数番目」が正しい。

左から数える場合に言い換えると、0-indexedで奇数位置(インデックス1,3,5…)を2倍する、という書き方になる。右からの奇数番目と左からの奇数インデックスが一致するのは14桁が偶数長だから。

実装

digits = 14桁の配列(左から順)
sum = 0
for i in 0..13:
d = digits[i]
if i % 2 == 1: # 左から数えて2,4,6...番目 = 右から数えて奇数番目
d = d * 2
if d >= 10: d = d - 9
sum += d
check = (10 - (sum % 10)) % 10

検算

49015420323751(14桁)で計算してみる。

左からの位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14
値 4 9 0 1 5 4 2 0 3 2 3 7 5 1
2倍対象 - ○ - ○ - ○ - ○ - ○ - ○ - ○
処理後 4 9 0 2 5 8 2 0 3 4 3 5 5 2

(2倍して10以上になった桁は9を引いている。9→9のままは18→1+8=9と同じなので変化なし)

合計 = 4+9+0+2+5+8+2+0+3+4+3+5+5+2 = 52

チェックデジット = (10 - 52%10) % 10 = (10-2)%10 = 8

→ 完成したIMEIは 490154203237518。これはLuhnアルゴリズムの説明でよく使われるサンプル値と一致する。

まとめると

  • 2倍する桁は「右から奇数番目」であって「右から偶数番目」ではない
  • 左から数えるなら0-indexedの奇数インデックス(2,4,6…番目)が対象で、これは右からの奇数番目と同じ集合を指している
  • 説明文だけを見て実装すると、右/左・奇数/偶数の組み合わせを取り違えやすいので、実装した後は既知のサンプル値(490154203237518など)で検算しておくのが確実