Faster string to double

I suggest C library function strtod, you should get around 2.5X improvement with this. That is about as good as it can get if one is trying to have a (relatively decent and robust) portable set of code.

This is as per I wrote in this comment, “This may include perhaps replacing … sections … with optimized C”

Click for code

String to Double

   use iso_c_binding, only: c_double, c_char, c_ptr, c_null_ptr, c_long
   interface
      function strtod( str, endptr ) result(d) bind(C, name="strtod" )
      ! <stdlib.h> :: double strtod(const char *str, char **endptr)
         import :: c_char, c_ptr, c_double
         ! Argument list
         character(kind=c_char,len=1), intent(in) :: str(*)
         type(c_ptr), intent(inout) :: endptr
         ! function result
         real(c_double) :: d 
      end function 
   end interface
   
   integer,parameter :: n = 1000000 !! number of values 
   
   integer :: i 
   character(len=30),dimension(:),allocatable :: strings
   real(c_double) :: rval, r_check
   integer :: ierr
   integer(c_long) :: start, finish, count_rate
   type(c_ptr) :: endptr
   
   ! create a list of values to parse
   allocate( strings(n) )
   do i = 1, n
      call RANDOM_NUMBER(rval)
      write(strings(i), '(E30.16)') rval
      if ( i == 1 ) r_check = rval 
   end do
   
   blk_io: block
      print *, "Block 1: formatted read toward string to double"
      read(strings(1),fmt=*,iostat=ierr) rval
      if ( abs(rval-r_check) > epsilon(r_check) ) then
         print *, "Warning: mismatch during formatted read."
         exit blk_io
      end if 

      call system_clock(start, count_rate)
      do i = 1, n
         read(strings(i),fmt=*,iostat=ierr) rval
      end do
      call system_clock(finish)
      write(*,'(A30,1X,F7.4,1X,A)') 'time * : ', (finish-start)/real(count_rate,c_double), ' seconds'
   end block blk_io
   print *
   blk_c: block
      print *, "Block 2: C strtod"
      endptr = c_null_ptr
      rval = strtod( strings(1), endptr )
      if ( abs(rval-r_check) > epsilon(r_check) ) then
         print *, "Warning: mismatch during strtod."
         exit blk_c
      end if 
      call system_clock(start, count_rate)
      do i = 1, n
         rval = strtod( strings(i), endptr )
      end do
      call system_clock(finish)
      write(*,'(A30,1X,F7.4,1X,A)') 'time * : ', (finish-start)/real(count_rate,c_double), ' seconds'
   end block blk_c

end

Block 1: formatted read toward string to double
time * : 0.4660 seconds

Block 2: C strtod
time * : 0.1800 seconds

4 Likes