Skip to content

Instantly share code, notes, and snippets.

@DSCF-1224
Created February 16, 2021 14:50
Show Gist options
  • Save DSCF-1224/28aec8d0173a473f20b6bf382da67d06 to your computer and use it in GitHub Desktop.
Save DSCF-1224/28aec8d0173a473f20b6bf382da67d06 to your computer and use it in GitHub Desktop.
Fortranでの整数の偶奇判定はbtestとmodのどちらが高速か
program main
! <module>s to import
use, intrinsic :: iso_fortran_env
use, non_intrinsic :: mod_is_even
use, non_intrinsic :: mod_test
! require all variables to be explicitly declared
implicit none
! constant(s) for this <program>
integer(INT32), parameter :: num_sample = 10_INT32 ** 7
integer(INT32), parameter :: num_trial = 10_INT32 ** 4
integer(INT32), parameter :: range_sample = 2_INT32 ** 30
! variable(s) for this <program>
integer(INT32), allocatable :: sample(:)
! STEP.01
! generate samples to execute the test
call generate_sample ( num_sample= num_sample, sample= sample, first= - range_sample, last= range_sample )
! STEP.02
! execute the test
call test_method ( is_even= is_even_bit, sample= sample(:), num_trial= num_trial )
call test_method ( is_even= is_even_mod, sample= sample(:), num_trial= num_trial )
end program main
FCFLAGS = -ffree-line-length-none -O2 -pedantic -std=f2008 -Wall -Wextra # -fbacktrace -fbounds-check
OBJS = ./mod_is_even.o ./mod_test.o ./main.o
main.exe: $(OBJS)
gfortran $(FCFLAGS) -o ./main.exe $(OBJS)
%.o: %.f08
gfortran $(FCFLAGS) -c $<
clean:
rm ./*.mod ./*.o
module mod_is_even
! <module>s to import
use, intrinsic :: iso_fortran_env
! require all variables to be explicitly declared
implicit none
! accessibility of the <subroutine>s and <function>s in this <module>
public :: is_even_bit
public :: is_even_mod
! contained <subroutine>s and <function>s are below
contains
pure function is_even_bit (i) result(is_even)
! argument(s) for this <function>
integer(INT32), intent(in) :: i
! return value of this <function>
logical :: is_even
is_even = .not. btest(i= i, pos= 0)
end function is_even_bit
pure function is_even_mod (i) result(is_even)
! argument(s) for this <function>
integer(INT32), intent(in) :: i
! return value of this <function>
logical :: is_even
is_even = (mod(a= i, p= 2_INT32) .eq. 0_INT32)
end function is_even_mod
end module mod_is_even
module mod_test
! <module>s to import
use, intrinsic :: iso_fortran_env
! require all variables to be explicitly declared
implicit none
! accessibility of the <subroutine>s and <function>s in this <module>
public :: generate_sample
public :: test_method
private :: random_number_int
! constant(s) for this <module>
integer(INT32), parameter, private :: num_sample_min = 0_INT32
integer(INT32), parameter, private :: num_trial_min = 0_INT32
integer(INT32), parameter, private :: stat_allocate_success = 0_INT32
! contained <subroutine>s and <function>s are below
contains
!
! [reference]
! - http://fortranwiki.org/fortran/show/random_number
!
pure function random_number_int (source, first, last) result(harvest)
! argument(s) for this <function>
real(REAL64) , intent(in) :: source ! random sample from intrinsic subroutine <RANDOM_NUMBER>
integer(INT32) , intent(in) :: first ! lowest integer in range of integers to get
integer(INT32) , intent(in) :: last ! highest integer in range of integers to get
! return value of this <function>
integer(INT32) :: harvest
harvest = first + floor( (last - first + 1_INT32) * source )
end function random_number_int
subroutine generate_sample (num_sample, sample, first, last)
! argument(s) for this <subroutine>
integer(INT32) , intent(in) :: num_sample ! number of samples to generate
integer(INT32) , intent(inout) , allocatable :: sample(:) ! array to store the generated samples
integer(INT32) , intent(in) :: first ! lowest integer in range of integers to get
integer(INT32) , intent(in) :: last ! highest integer in range of integers to get
! variable(s) for this <subroutine>
integer :: buffer_stat
real(REAL64) :: buffer_rand
integer(INT32) :: iter
! STEP.01
! check the given arguments
if ( num_sample .le. num_sample_min ) then
write(unit= ERROR_UNIT, fmt='(A)') 'The number of samples must be greater than zero.'
stop
end if
if (first .ge. last) then
write(unit= ERROR_UNIT, fmt='(A)') 'The range of integers to get is invalid.'
stop
end if
! STEP.02
! allocate the array to store the generated samples
allocate( sample(num_sample) , stat= buffer_stat )
select case (buffer_stat)
case(stat_allocate_success)
! Nothing to do in this block
case default
write(unit= ERROR_UNIT, fmt='(A)') 'Falied to allocate an array to store the generated samples.'
write(unit= ERROR_UNIT, fmt='(A,1X,I0)') 'Error Code >', buffer_stat
stop
end select
! STEP.03
! generate & store the samples for the test
do iter = 1_INT32 , num_sample , 1_INT32
call random_number(buffer_rand)
sample(iter) = random_number_int(source = buffer_rand, first= first, last= last)
end do
! STEP.END
return
end subroutine generate_sample
subroutine test_method (is_even, sample, num_trial)
! argument(s) for this <function>
interface
pure function is_even (i)
! <module>s to import
use, intrinsic :: iso_fortran_env
! argument(s) for this <function>
integer(INT32), intent(in) :: i
! return value of this <function>
logical :: is_even
end function is_even
end interface
integer(INT32), intent(in) :: sample(:) ! samples to test the method
integer(INT32), intent(in) :: num_trial ! number of trials
! variable(s) for this <subroutine>
logical :: buffer_stat
integer(INT32) :: iter_sample
integer(INT32) :: iter_trial
integer(INT64) :: clock_count_end
integer(INT64) :: clock_count_max
integer(INT64) :: clock_count_rate
integer(INT64) :: clock_count_start
! STEP.01
! check the given arguments
if ( num_trial .le. num_trial_min ) then
write(unit= ERROR_UNIT, fmt='(A)') 'The number of trials must be greater than zero.'
stop
end if
! STEP.02
! record the <SYSTEM_CLOCK> before starting the target process
call system_clock(count= clock_count_start, count_rate= clock_count_rate, count_max= clock_count_max)
! STEP.03
! execute the target process
do iter_trial = 1_INT32 , num_trial , 1_INT32
do iter_sample = 1_INT32 , size(sample) , 1_INT32
buffer_stat = is_even( sample(iter_sample) )
end do
end do
! STEP.04
! record the cpu time after the target process
call system_clock(count= clock_count_end)
! STEP.05
! show the result
write( unit= OUTPUT_UNIT, fmt='("system clock >",1X,I20)' ) clock_count_end - clock_count_start
! STEP.END
return
end subroutine test_method
end module mod_test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment