Speed of atoi and atof vs. internal read

@Beliavsky ,

Have you checked in Fortran stdlib to see what may be available now?

You will know this thread for options relative to C strtod.

As to “string to int”, you can take inspiration from @lkedward in this thread and trivially get Fortran to give better performance.

C:\Temp>gfortran -O3 p.f90 -o p.exe

C:\Temp>p.exe
               C Fortran   ratio
   times  0.4375  0.1719  0.3929


       #    mean     min     max   first    last maxdiff
10000000    85.3 -500000  499999 -269279   18973       0
Click to see code
program main
use, intrinsic :: iso_c_binding, only: c_char, c_null_char
implicit none
interface
   function atoi(in) bind(c)
   use, intrinsic    :: iso_c_binding
   integer(c_int)    :: atoi
   character(c_char) :: in(*)
   end function
end interface
integer :: j,iran
integer, parameter :: nread = 10**7, nt = 3
character(len=10,kind=c_char), allocatable :: digits(:), cdigits(:)
real :: times(nt),dt(nt-1),xran
integer, allocatable :: iran_c(:),iran_f(:)
allocate (digits(nread),cdigits(nread),iran_c(nread),iran_f(nread))
do j=1,nread
   call random_number(xran)
   iran = 10**6*(xran-0.5) ! random integer
   write (digits(j),"(i0)") iran ! write integer to string
   cdigits(j) = trim(digits(j)) // c_null_char ! create C string
end do
call cpu_time(times(1))
do j=1,nread ! read integers from C strings using C atoi
   iran_c(j) = atoi(cdigits(j))
end do
call cpu_time(times(2))
iran_f = parse_int( digits )  !<-- simple elemental parsing
call cpu_time(times(3))
dt = times(2:nt)-times(1:nt-1)
print "(4a8)","","C","Fortran","ratio"
print "(a8,3f8.4,/)","times",dt,dt(2)/dt(1)
print "(/,*(a8))","#","mean","min","max","first","last","maxdiff"
print "(i8,f8.1,*(i8))",nread,sum(dble(iran_c))/nread,minval(iran_c),maxval(iran_c), &
                     iran_c(1),iran_c(nread),maxval(abs(iran_c-iran_f))
contains

   ! Simple variant for base 10 of function by @lkedward toward Julia microbenchmark
   elemental function parse_int(s) result(n)

      ! Argument list
      character(len=*), intent(in) :: s
      ! Function result
      integer :: n

      ! Local variables
      integer :: i, d, sign
      character :: c

      n = 0
      sign = 1
      loop_digits: do i = 1, len_trim(s)
         c = s(i:i)
         d = 0
         select case ( ichar(c) )
            case ( ichar('0'):ichar('9') )
               d = ichar(c) - ichar('0')
            case ( ichar('-') )
               sign = -1
               cycle loop_digits
            case ( ichar(' ') )
               cycle loop_digits
            case default 
               error stop "parse error"
         end select
         n = n*10 + d
      end do loop_digits
      n = sign*n

   end function

end program main
1 Like