マイナンバーのチェックデジットを計算する Fortran 2003


Fortran タグで下記記事が流れてきたので、遅ればせながら日曜午後の暇つぶしにと参加してみました。
色々な言語でマイナンバーのチェックデジットを計算したかった

計算方法などは、以下を参照しました。
マイナンバーのチェックデジットを計算する - Qiita

マイナンバー イメージ画像

ソース・プログラム

Fortran 2003 なのはコマンドライン引数を取るところだけで、残りは Fortran90/95 水準です。

    module m_mynum
      implicit none
    contains
      pure integer function ichk_sum(ip)
        integer, intent(in) :: ip(11)
        integer :: i, iq(11)
        forall (i = 1:11) iq(i) = mod(i - 1, 6) + 2 
        ichk_sum = 11 - mod(sum(ip * iq), 11)
        if (ichk_sum >= 10) ichk_sum = 0
      end function ichk_sum  

      subroutine chk_mynumber(c)
        character, intent(in) :: c(12)
        integer :: m(12)
        m = iachar(c) - iachar('0') ! change to ascii code
        if (m(12) == ichk_sum( m(11:1:-1) )) then ! reverse order
          print *, 'check matched!'
        else
          print *, 'check failed!'
        end if
      end subroutine chk_mynumber   
    end module m_mynum

    program mynum
      use m_mynum
      implicit none
      character (len = 80) :: buff
      call get_command_argument(1, buff) ! F2003
      if (len_trim(buff) == 12) then
        call chk_mynumber(transfer(buff, ' ', size = 12))  ! string to chr-array
      else
        print *, 'input must be 12 digits long'  
      end if    
    end program mynum

チェックサム関数の pure プレフィックスは、今の場合ただの飾りです。

Transfer 関数で文字列を、文字配列に直しています。文字配列にすると、関数の elemental な性質が使えるのでループ変数で回す必要がなくなります。intel 拡張の [1:11] での数列生成を用いれば、forall ループもいらなくなるのですが、ここは標準に敬意を払って・・・

ichar と iachar の違いは、処理系の文字コードか ASCII コードかの違いです。Fortran 界では長年 IBM の EBCDIC が正字だったので二通りの関数が用意してあります。現在では ASCII に一統された感があるので、あまり気にしなくても問題ありません。EBCDIC では文字が連続して並んでいないので、文字コードの連続性を仮定した ASCII コードでのテクニックがしばしば破綻します。

実行結果

E:\Projects\Console4\mynum\Debug>mynum 12345678901
 input must be 12 digits long

E:\Projects\Console4\mynum\Debug>mynum 123456789010
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789011
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789012
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789013
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789014
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789015
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789016
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789017
 check failed!

E:\Projects\Console4\mynum\Debug>mynum 123456789018
 check matched!

E:\Projects\Console4\mynum\Debug>mynum 123456789019
 check failed!