LoginSignup
4
4

More than 5 years have passed since last update.

マイナンバーのチェックデジットの検算をざっくり1割くらい高速化する(計ってないので知らんけど)

Last updated at Posted at 2015-11-03

まずは計算方法をじっと考える

承前

まず、検査用数字(チェックデジット)の算出方法をじっと眺めます。プログラマ目線で眺めていると、要するに次のような手順で計算すればよい、ということがわかります。

  1. $P, Q$ を次のようにおく。$P$は、マイナンバーのうちチェックデジットを除く11桁の番号を要素として含むリストとし、$P$の要素$P_{0}$は11桁の番号のうち1桁目の数値を表すこととする。$Q$の各要素$Q_n$は$n \bmod 6 + 2$として求める。ただし$n$は$0 \le n \le 10$とする。
    • $P = (P_{10}, P_{9}, P_{8}, ..., P_{0})$
    • $Q = (Q_{10}, Q_{9}, Q_{8}, ..., Q_{0}) = (6, 5, 4, 3, 2, 7, 6, 5, 4, 3, 2)$
  2. $r = (11 - \sum_{n=1}^{11} P_n \cdot Q_n \bmod 11) \bmod 10$ を求め、$r$を検査用数字として出力する。

ここまでわかれば、あとはどの言語でどう書くにしても簡単です。条件分岐なども登場しないため、たぶん実行速度も速くなっているでしょう。
では、さっそく書いてみましょう。

Ruby

verify_my_number.rb
def verify_my_number(my_number)
  remain, given_check_digit = my_number.divmod(10)
  check_digit = 0

  11.times do |i|
    remain, p_i = remain.divmod(10)
    check_digit += p_i * (i % 6 + 2)
  end

  (11 - check_digit % 11) % 10 == given_check_digit
end

Perl

verify_my_number.pl
sub verify_my_number {
    my ($my_number) = @_;
    my $given_check_digit = $my_number % 10;
    my $check_digit = 0;

    for (my $i = 0; $i < 11; $i++) {
        $my_number /= 10;
        $check_digit += ($my_number % 10) * ($i % 6 + 2);
    }

    return (11 - $check_digit % 11) % 10 == $given_check_digit;
}

Rubyの場合とそれほど差が無くて面白くないので、一応、別の書き方も試してみます。
書いていて少し楽しい、というだけで、速度の面での優位性はないと思いますが。

verify_my_number2.pl
sub verify_my_number {
    my ($my_number) = @_;
    my $check_digit = 0;

    map {
        $check_digit += $my_number / (10 ** ($_ + 1)) % 10 * ($_ % 6 + 2);
    } (0 .. 10);

    return (11 - $check_digit % 11) % 10 == $my_number % 10;
}

C

verify_my_number.c
int
verify_my_number(long long int my_number)
{
        int check_digit = 0;
        int given_check_digit = my_number % 10;

        for (int i = 0; i < 11; i++) {
                my_number /= 10;
                check_digit += (my_number % 10) * (i % 6 + 2);
        }

        return (11 - check_digit % 11) % 10 == given_check_digit;
}

Go

verify_my_number.go
func verify_my_number(my_number int) bool {
    check_digit := 0
    given_check_digit := my_number % 10

    for i := 0; i < 11; i++ {
        my_number /= 10
        check_digit += (my_number % 10) * (i % 6 + 2)
    }

    return (11 - check_digit % 11) % 10 == given_check_digit
}

bash

verify_my_number.sh
function verify_my_number {
    n=`printf %012d $1`
    given_check_digit=$(($1 % 10))
    check_digit=`echo -n $n|grep -o .|paste -d\* - <(echo -n '654327654320'|grep -o .)|paste -d+ - - - - - - - - - - - -|sed -e 's/^/echo $(((11-(/' -e 's/$/)%11)%10))/'|sh`
    [ $check_digit -eq $given_check_digit ] && echo 'OK' || echo 'NG'
}

Excel

チェックデジットの算出だけなら次のように書けます。

=MOD(
11 - MOD(
(MOD(QUOTIENT($A1, 10000000000), 10) * 6 +
MOD(QUOTIENT($A1, 1000000000), 10) * 5 +
MOD(QUOTIENT($A1, 100000000), 10) * 4 +
MOD(QUOTIENT($A1, 10000000), 10) * 3 +
MOD(QUOTIENT($A1, 1000000), 10) * 2 +
MOD(QUOTIENT($A1, 100000), 10) * 7 +
MOD(QUOTIENT($A1, 10000), 10) * 6 +
MOD(QUOTIENT($A1, 1000), 10) * 5 +
MOD(QUOTIENT($A1, 100), 10) * 4 +
MOD(QUOTIENT($A1, 10), 10) * 3 +
MOD($A1, 10) * 2),
11),
10)

Python

Pythonよくわからないけど、多分こんな感じ?
それほど速くはないと思います。

verify_my_number.py
def verify_check_digit(my_number):
    product = sum([
                    (my_number / (10 ** (i + 1)) % 10) * (i % 6 + 2)
                    for i in range(0, 11)
                 ])
    return (11 - product % 11) % 10 == my_number % 10
4
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4