73 lines
3 KiB
Fortran
73 lines
3 KiB
Fortran
module damm_algorithm
|
|
implicit none
|
|
private
|
|
public :: damm_check ! Expose only the damm_check function to external code
|
|
|
|
contains
|
|
|
|
!---------------------------------------------------------------------
|
|
! Function: damm_check
|
|
! Purpose : Validates a digit string using the Damm algorithm
|
|
! Input : digit - a character string of numeric digits ('0' to '9')
|
|
! Output : is_valid - .TRUE. if the check digit validates, .FALSE. otherwise
|
|
!---------------------------------------------------------------------
|
|
function damm_check(digit) result(is_valid)
|
|
use iso_fortran_env, only: int8 ! Use portable 8-bit integer type
|
|
character(len=*), intent(in) :: digit
|
|
logical :: is_valid
|
|
integer(kind=int8) :: i, d, id
|
|
|
|
!------------------------------------------------------------------
|
|
! Damm operation table: a 10x10 quasigroup matrix used for validation
|
|
! Note: Fortran stores arrays in column-major order, meaning that
|
|
! array constructors fill columns first, not rows.
|
|
! To preserve the intended row-wise layout of the table,
|
|
! we use TRANSPOSE(RESHAPE(...)) to correct the orientation.
|
|
!------------------------------------------------------------------
|
|
integer(kind=int8), parameter :: optable(0:9, 0:9) = transpose(reshape( &
|
|
[integer(kind=int8) :: &
|
|
0, 3, 1, 7, 5, 9, 8, 6, 4, 2, & ! Row 0
|
|
7, 0, 9, 2, 1, 5, 4, 8, 6, 3, & ! Row 1
|
|
4, 2, 0, 6, 8, 7, 1, 3, 5, 9, & ! Row 2
|
|
1, 7, 5, 0, 9, 8, 3, 4, 2, 6, & ! Row 3
|
|
6, 1, 2, 3, 0, 4, 5, 9, 7, 8, & ! Row 4
|
|
3, 6, 7, 4, 2, 0, 9, 5, 8, 1, & ! Row 5
|
|
5, 8, 6, 9, 7, 2, 0, 1, 3, 4, & ! Row 6
|
|
8, 9, 4, 5, 3, 6, 2, 0, 1, 7, & ! Row 7
|
|
9, 4, 3, 8, 6, 1, 7, 2, 0, 5, & ! Row 8
|
|
2, 5, 8, 1, 4, 3, 6, 7, 9, 0 ], & ! Row 9
|
|
shape=[10, 10])) ! Reshape into 10x10, then transpose to fix layout
|
|
|
|
! Initialize the interim digit to zero
|
|
id = 0
|
|
|
|
! Loop over each character in the input string
|
|
do i = 1, len(digit)
|
|
! Convert character to integer digit (ASCII math)
|
|
d = iachar(digit(i:i)) - iachar('0')
|
|
|
|
! Validate that the character is a digit
|
|
if (d < 0 .or. d > 9) then
|
|
error stop 'Invalid input: Not a digit in string'
|
|
end if
|
|
|
|
! Apply Damm algorithm step: lookup in the operation table
|
|
id = optable(id, d)
|
|
end do
|
|
|
|
! Final check: if result is zero, the input is valid
|
|
is_valid = (id == 0)
|
|
end function damm_check
|
|
|
|
end module damm_algorithm
|
|
|
|
program test_damm
|
|
use damm_algorithm
|
|
implicit none
|
|
|
|
write(*, '(A,L1,A)') 'Damm check for "5724": ', damm_check('5724'), ' (should be .TRUE.)'
|
|
write(*, '(A,L1,A)') 'Damm check for "5727": ', damm_check('5727'), ' (should be .FALSE.)'
|
|
write(*, '(A,L1,A)') 'Damm check for "112946": ', damm_check('112946'), ' (should be .TRUE.)'
|
|
write(*, '(A,L1,A)') 'Damm check for "112949": ', damm_check('112949'), ' (should be .FALSE.)'
|
|
end program test_damm
|
|
END
|