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