科目Bのチェックディジット問題の解き方|桁ごとの重みを表で追う
掛け算と足し算だけなのに、どの桁に何を掛けたのか分からなくなる。
科目Bの問題で、数字の並びから最後の1桁を計算するコードを見て、手が止まったことはありませんか?
重み、合計、余り、そして10から引く計算。式がいくつも重なって、どこで何をしているのかが見えなくなってしまう人も多いのではないでしょうか。
大丈夫です。チェックディジットの問題は、桁ごとに決まった数を掛けて足し、最後に余りを使って1桁を決めているだけです。
私はエンジニアとして10年以上、Webシステムの開発や運用に携わってきました。実務でも、会員番号や商品コードの入力チェックで、チェックディジットの計算を組み込む場面が何度かありました。
ある時は、正しい番号なのにエラーになる、という問い合わせが続きました。調べてみると、重みを掛け始める桁が左右逆になっていて、小さな番号で桁ごとの計算を表に書き出したことで、ようやく原因が分かりました。
この記事では、チェックディジットの問題を、科目Bの解き方に合わせて5つの段階で紹介します。科目B全体の中でこうした問題がどんな位置にあるのかを先に確かめたい人は、親記事から読んでおくと流れがつかみやすくなります。
【関連記事】基本情報技術者試験の科目Bとは?擬似言語・アルゴリズム対策を初心者向けに解説
チェックディジットの問題は何を聞いているのか¶
最初に、チェックディジットとはどういうものかを短く押さえておきましょう。チェックディジットとは、番号の入力ミスを見つけるために、番号の末尾などに付け足す1桁の数字のことです。
元の番号の各桁に決まった重みを掛けて合計し、その合計の余りから1桁を決める処理が、チェックディジットの問題の正体です。
身近なところでは、商品のバーコードに使われるJANコードの最後の1桁がチェックディジットです。読み取った番号から同じ計算をして、最後の1桁と合わなければ、読み取りか入力のどこかが間違っていると分かります。
人が番号を手で打つと、1桁だけ打ち間違えたり、隣どうしの数字を入れ替えてしまったりします。そうしたミスを、計算だけで見つけられるようにする工夫だと考えてください。
代表的な計算方法を表で比べる¶
チェックディジットの計算方法にはいくつか種類があります。科目Bでは問題文の中で計算方法が説明されるので、暗記する必要はありません。
ただ、よく使われる形を知っておくと、問題文を読む速さが変わります。代表的なものを表に整理しました。
| 方式 | 重みの付け方 | 割る数 | 最後の1桁の決め方 |
|---|---|---|---|
| JANコード(13桁) | 左から1、3、1、3と交互 | 10 | 10 から合計の余りを引き、10 なら 0 にする |
| ISBN(10桁の旧形式) | 左から 10、9、8 と1ずつ減らす | 11 | 合計が 11 で割り切れるように決め、10 になるときは X と書く |
| 問題文独自の方式 | 問題文で指定 | 問題文で指定 | 問題文で指定 |
表を見ると、どの方式も、重みを掛けて足す、割った余りを見る、という2つの部分でできていることが分かります。違うのは重みの並びと割る数だけです。
科目Bでは、3行目の問題文独自の方式が出ることも珍しくありません。だからこそ、方式を覚えるより、問題文から重みと割る数を読み取る力のほうが大切です。
基数変換や剰余の問題との違い¶
チェックディジットとよく似た問題に、数をn進数に直す基数変換の問題があります。どちらも余りを使いますが、基数変換は余りを何度も取って桁を作り出すのに対し、チェックディジットは合計の余りを最後に1回だけ取ります。
数を桁に分解して余りと商を繰り返す処理は、基数変換の記事で詳しく扱っています。
【関連記事】科目Bの基数変換問題の解き方|n進数への変換を余りと商で追う
また、mod という記号そのものの意味に不安がある場合は、先に文法の記事で確かめておくと安心です。
【関連記事】擬似言語の余り(剰余)と割り算がわからない人へ|偶数判定と桁の取り出しを解説
まず目を付ける場所¶
チェックディジットが何かつかめたら、次はコードのどこから読むかを決めます。この問題では、目を付ける場所が3つあります。
ひとつ目は重みをどう決めているか、ふたつ目は合計にどう足しているか、みっつ目は最後に余りをどう使っているかです。この3か所を確かめれば、どの方式で計算しているのかが分かります。
重みはどこで決まっているか¶
最初に確かめたいのが、重みの決め方です。重みが配列で渡されているのか、ループの添字から計算しているのかで、読み方が変わります。
添字から計算している場合は、i mod 2 のような式がよく使われます。i が奇数のときと偶数のときで、どちらの重みが掛かるのかを、最初の2回ぶんだけ手で確かめておきましょう。
ここで大事なのが、左から数えているのか右から数えているのかです。番号の桁数が奇数か偶数かで、左から数えた位置と右から数えた位置の偶奇が入れ替わることがあるからです。
合計に何を足しているか¶
次に見るのが、合計の変数に足している式です。多くの場合は、その桁の数字と重みを掛けたものを足しています。
方式によっては、掛け算の結果が2桁になったとき、十の位と一の位を足して1桁にしてから合計に加えるものもあります。合計の行の周りに、もう1つ mod や ÷ が出てきたら、この処理を疑ってください。
最後に余りをどう使っているか¶
最後に見るのが、return の行や、ループのあとの計算です。合計の余りをそのまま返すのか、割る数から引くのか、さらにもう一度余りを取るのかを確かめます。
この部分は選択肢の差が最も出やすい場所です。余りが0になったときに何が返るかを、必ず確かめるようにしましょう。
例題:重み1と3を交互に掛けて最後の1桁を求める¶
ここからは、実際の例題で追い方を確かめます。この記事の例題は説明のために作成したもので、IPA の公開問題そのものではありません。
次のプログラムは、整数型の配列 digits に番号の各桁が左から順に入っているとき、チェックディジットを返す関数です。左から1桁目、3桁目のような奇数番目の桁には重み1を、偶数番目の桁には重み3を掛けます。配列の添字は1から始まります。
○整数型: checkDigit(整数型の配列: digits)
整数型: i, weight
整数型: total ← 0
for (i を 1 から digits の要素数 まで 1 ずつ増やす)
if (i mod 2 が 1 と等しい)
weight ← 1
else
weight ← 3
endif
total ← total + digits[i] × weight
endfor
return (10 − (total mod 10)) mod 10
checkDigit は、i が奇数なら重みを1に、偶数なら3にして、桁の数字と掛けたものを total に足していきます。ループが終わったら、total を10で割った余りを10から引き、その結果をもう一度10で割った余りを返します。
では、checkDigit({4, 9, 1, 2, 0, 6}) の戻り値は何になるでしょうか?
トレース表で桁ごとの重みを追う¶
頭の中だけで掛け算と足し算を続けると、どの桁に3を掛けたのかが分からなくなりがちです。そこで、ループ1回ごとに、i、digits[i]、weight、掛けた結果、足したあとの total をトレース表に書きます。
ポイントは、掛けた結果の列を独立させることです。足す前の値を残しておけば、計算をやり直すときにどの行で間違えたのかがすぐに分かります。
| i | digits[i] | weight | digits[i] × weight | 足したあとの total |
|---|---|---|---|---|
| 1 | 4 | 1 | 4 | 4 |
| 2 | 9 | 3 | 27 | 31 |
| 3 | 1 | 1 | 1 | 32 |
| 4 | 2 | 3 | 6 | 38 |
| 5 | 0 | 1 | 0 | 38 |
| 6 | 6 | 3 | 18 | 56 |
ループが終わった時点で total は56です。56を10で割った余りは6なので、10から引くと4になります。
最後に4を10で割った余りを取っても4のままです。したがって、戻り値は4になります。
トレース表の書き方そのものに慣れていない場合は、こちらの記事で基本から確認できます。
【関連記事】擬似言語のトレース表の書き方|科目Bで変数の値を追う手順を解説
正しい番号かどうかを確かめる計算¶
チェックディジットは、求めるだけでなく、確かめる側の計算もセットで出ることがあります。確かめる側では、チェックディジットまで含めた全部の桁に同じ重みを掛けて足します。
例題の番号に4を付けた {4, 9, 1, 2, 0, 6, 4} で考えてみましょう。7桁目は奇数番目なので重みは1、合計は56に4を足して60になります。
60は10で割り切れます。合計が割る数で割り切れれば正しい番号、割り切れなければどこかに誤りがある、というのが確かめる側の考え方です。
合計の余りが0になる例も試す¶
例題だけでは、最後の mod 10 が何のためにあるのかが見えません。そこで、合計の余りが0になる番号でも試しておきましょう。
{2, 6, 0, 0, 0, 0} なら、2 × 1 と 6 × 3 を足して total は20です。20を10で割った余りは0なので、10から引くと10になります。
チェックディジットは1桁でなければならないので、10のままでは困ります。最後にもう一度10で割った余りを取ることで、10が0に直されるのです。
間違いやすい選択肢の見分け方¶
チェックディジットの問題では、重みの順番や余りの取り方を少しだけずらした選択肢が並びます。どんな誤りが用意されやすいのかを知っておけば、選択肢を見た瞬間に候補を絞れます。
例題の checkDigit({4, 9, 1, 2, 0, 6}) を使って、よくある誤りを表にまとめました。
| 誤りの種類 | 選択肢の例 | 計算結果 | 起きること |
|---|---|---|---|
| 重みの向きが逆 | 奇数番目に3、偶数番目に1 | total は 32、戻り値は 8 | 桁と重みの組み合わせがすべてずれる |
| 10 から引き忘れ | total mod 10 をそのまま返す | 6 | 確かめる側の合計が割り切れない |
| 最後の mod を省く | 10 − (total mod 10) を返す | この例では 4 | 余りが0のとき10が返ってしまう |
| 重みを掛け忘れ | 桁の数字をそのまま足す | total は 22、戻り値は 8 | 入れ替えのミスを見つけられない |
3行目の誤りは、例題の番号では正しい答えと同じ4になってしまいます。答えが合ったから正しい、と決めつけず、余りが0になる番号でも試すのが確実です。
1つの例で答えが合っても安心しない¶
選択肢を絞るときは、例題とは別に、自分で小さな番号を2つ用意すると安全です。1つは普通の番号、もう1つは合計の余りが0になる番号にします。
この2つで答えが合えば、余りの扱いの誤りはほぼ見分けられます。桁数を2桁か3桁にしておけば、計算もすぐに終わります。
重みの向きは位置を言葉にする¶
重みの向きで迷ったら、左から1桁目には何を掛けるのか、と言葉にして問題文と照らし合わせましょう。冒頭でお話しした番号のエラーも、原因はこの向きでした。
問題文が右から数えて重みを決めている場合は、コードの中で添字を逆から回しているか、桁数から位置を計算し直しているはずです。どちらの書き方なのかを、ループの範囲と if の条件の両方で確かめてください。
重みを掛ける意味を知っておく¶
重みを掛けずに足すだけだと、隣どうしの数字を入れ替えても合計が変わりません。たとえば 1、2 と 2、1 は、どちらも合計が3です。
交互に1と3を掛けておけば、1 × 1 + 2 × 3 は7、2 × 1 + 1 × 3 は5となり、入れ替えに気づけます。重みが何のためにあるのかを知っておくと、重みを掛け忘れた選択肢を自信を持って外せます。
Giji Academy のシミュレーターで動かす¶
紙のトレース表で動きをつかんだら、最後は実際に動かして確かめましょう。掛け算と余りが重なる処理ほど、動かして見る効果は大きくなります。
Giji Academy の擬似言語シミュレーターでは、擬似言語のコードを1行ずつ実行し、変数の値が変わる様子を目で確かめられます。自分で書いたトレース表と見比べながら進めると、どの桁で予想とずれたのかがすぐに分かります。
試すときは、まず正しい checkDigit を動かして、total が56まで増えて4が返るのを確かめてください。そのあと、weight の1と3を入れ替えて、戻り値が8に変わる様子を見ると、重みの向きが答えを大きく変えることが体で分かります。
慣れてきたら、最後の mod 10 を消して {2, 6, 0, 0, 0, 0} を渡したり、確かめる側の関数を自分で書いてみたりしましょう。余りの扱いがどこで効いてくるのかが、少しずつ見えてくるはずです。
まずはGiji Academy の擬似言語シミュレーターで講座を選び、桁ごとに重みが掛かって合計が伸びていく様子を確かめてみてください。
まとめ¶
科目Bのチェックディジットの問題は、特別な数学の知識を問うものではありません。桁ごとに重みを掛けて足し、最後に余りを使って1桁を決める、という手順を表に書いて追えば、落ち着いて解けます。
この記事でお伝えした5つの段階を振り返っておきましょう。
| 段階 | やること |
|---|---|
| 1 設問を読む | 重みの並び、割る数、最後の1桁の決め方を問題文から読み取る |
| 2 目を付ける | 重みの決め方、合計に足す式、最後の余りの使い方の3か所を見る |
| 3 トレースする | i、桁の数字、重み、掛けた結果、足したあとの合計を1回ずつ表に書く |
| 4 選択肢を見分ける | 重みの向き、引き忘れ、最後の mod、掛け忘れを小さな例で試す |
| 5 動かす | 正しいコードとずれたコードをシミュレーターで動かし、表と見比べる |
最初は、3桁から6桁くらいの短い番号で十分です。何度か表を書くうちに、i mod 2 の式を見ただけで、どの桁にどの重みが掛かるのかが分かるようになります。
重みは左から何桁目かで決まる。余りが0になる番号でも必ず試す。 この2つを習慣にしておけば、チェックディジットの問題にも自信を持って向き合えます。次に番号の最後の1桁を求めるコードに出会ったら、まずは1桁目と2桁目に掛かる重みから表に書いてみてください。