Skip to content

Commit 5d380a0

Browse files
committed
add support for extended double precision
1 parent 94bf4a8 commit 5d380a0

File tree

1 file changed

+106
-11
lines changed

1 file changed

+106
-11
lines changed

src/stdlib_str2num.fypp

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
!> difference rel : 0.3300E-029%
2424

2525
module stdlib_str2num
26-
use stdlib_kinds, only: sp, dp, qp, int8, int16, int32, int64
26+
use stdlib_kinds, only: sp, dp, xdp, qp, int8, int16, int32, int64
2727
use, intrinsic:: ieee_arithmetic, only: ieee_value, ieee_positive_inf, ieee_quiet_nan
2828
implicit none
2929
private
@@ -44,25 +44,19 @@ module stdlib_str2num
4444

4545
interface to_num
4646
#:for k1, t1 in (INT_KINDS_TYPES + REAL_KINDS_TYPES)
47-
#:if k1 != "xdp"
4847
module procedure to_${k1}$
49-
#:endif
5048
#:endfor
5149
end interface
5250

5351
interface to_num_p
5452
#:for k1, t1 in (INT_KINDS_TYPES + REAL_KINDS_TYPES)
55-
#:if k1 != "xdp"
5653
module procedure to_${k1}$_p
57-
#:endif
5854
#:endfor
5955
end interface
6056

6157
interface to_num_base
6258
#:for k1, t1 in (INT_KINDS_TYPES + REAL_KINDS_TYPES)
63-
#:if k1 != "xdp"
6459
module procedure to_${k1}$_base
65-
#:endif
6660
#:endfor
6761
end interface
6862

@@ -73,7 +67,6 @@ module stdlib_str2num
7367
!---------------------------------------------
7468

7569
#:for k1, t1 in (INT_KINDS_TYPES + REAL_KINDS_TYPES)
76-
#:if k1 != "xdp"
7770
elemental function to_${k1}$(s,mold) result(v)
7871
! -- In/out Variables
7972
character(*), intent(in) :: s !> input string
@@ -102,14 +95,12 @@ module stdlib_str2num
10295
if(present(stat)) stat = err
10396
end function
10497

105-
#:endif
10698
#:endfor
10799
!---------------------------------------------
108100
! String To Number Implementations
109101
!---------------------------------------------
110102

111103
#:for k1, t1 in INT_KINDS_TYPES
112-
#:if k1 != "xdp"
113104
elemental subroutine to_${k1}$_base(s,v,p,stat)
114105
!> Return an unsigned 32-bit integer
115106
! -- In/out Variables
@@ -137,7 +128,6 @@ module stdlib_str2num
137128
stat = 0
138129
end subroutine
139130

140-
#:endif
141131
#:endfor
142132

143133
elemental subroutine to_sp_base(s,v,p,stat)
@@ -331,6 +321,111 @@ module stdlib_str2num
331321
stat = 0
332322
end subroutine
333323

324+
#:if WITH_XDP
325+
elemental subroutine to_xdp_base(s,v,p,stat)
326+
integer, parameter :: wp = xdp
327+
!> Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
328+
! -- In/out Variables
329+
character(*), intent(in) :: s !> input string
330+
real(wp), intent(inout) :: v !> Output real value
331+
integer(int8), intent(out) :: p !> last position within the string
332+
integer(int8), intent(out) :: stat !> status upon success or failure to read
333+
334+
! -- Internal Variables
335+
integer(int8), parameter :: nwnb = 50 !> number of whole number factors
336+
integer(int8), parameter :: nfnb = 64 !> number of fractional number factors
337+
integer :: e
338+
real(wp), parameter :: whole_number_base(nwnb) = [(10._wp**(nwnb-e),e=1,nwnb)]
339+
real(wp), parameter :: fractional_base(nfnb) = [(10._wp**(-e),e=1,nfnb)]
340+
real(wp), parameter :: expbase(nwnb+nfnb) = [whole_number_base, fractional_base]
341+
342+
integer(int8) :: sign, sige !> sign of integer number and exponential
343+
integer, parameter :: maxdpt = 19 !> Maximum depth to read values on int_dp
344+
integer(dp) :: int_dp1, int_dp2 !> long integers to capture whole and fractional part
345+
integer :: i_exp !> integer to capture exponent number
346+
integer :: exp_aux
347+
integer(int8) :: i, pP, pE, val , resp, icount, aux
348+
!----------------------------------------------
349+
stat = 23 !> initialize error status with any number > 0
350+
!----------------------------------------------
351+
! Find first non white space
352+
p = mvs2nwsp(s)
353+
!----------------------------------------------
354+
! Verify leading negative
355+
sign = 1
356+
if( iachar(s(p:p)) == minus_sign+digit_0 ) then
357+
sign = -1 ; p = p + 1
358+
end if
359+
if( iachar(s(p:p)) == Inf ) then
360+
v = sign*ieee_value(v, ieee_positive_inf); return
361+
else if( iachar(s(p:p)) == NaN ) then
362+
v = ieee_value(v, ieee_quiet_nan); return
363+
end if
364+
!----------------------------------------------
365+
! read whole and fractional number using two int64 values
366+
pP = 127
367+
int_dp1 = 0; int_dp2 = 0; icount = 0; aux = 1
368+
do i = p, min(2*maxdpt+p-1,len(s))
369+
val = iachar(s(i:i))-digit_0
370+
if( val >= 0 .and. val <= 9 ) then
371+
icount = icount + 1
372+
if(icount<=maxdpt)then
373+
int_dp1 = int_dp1*10 + val
374+
else if(icount<2*maxdpt)then
375+
int_dp2 = int_dp2*10 + val
376+
end if
377+
else if( val == period ) then
378+
pP = i; aux = 0
379+
else
380+
exit
381+
end if
382+
end do
383+
pE = i ! Fix the exponent position
384+
do while( i<=len(s) )
385+
val = iachar(s(i:i))-digit_0
386+
if( val < 0 .or. val > 9 ) exit
387+
i = i + 1
388+
end do
389+
p = i
390+
resp = pE-min(pP,p) ! If no decimal indicator found it is taken as being in the current p position
391+
if( resp <= 0 ) resp = resp+1
392+
!----------------------------------------------
393+
! Get exponential
394+
sige = 1
395+
if( p<len(s) ) then
396+
if( any([le,BE,ld,BD]+digit_0==iachar(s(p:p))) ) p = p + 1
397+
if( iachar(s(p:p)) == minus_sign+digit_0 ) then
398+
sige = -1
399+
p = p + 1
400+
else if( iachar(s(p:p)) == plus_sign+digit_0 ) then
401+
p = p + 1
402+
end if
403+
end if
404+
405+
i_exp = 0
406+
do while( p<=len(s) )
407+
val = iachar(s(p:p))-digit_0
408+
if( val >= 0 .and. val <= 9) then
409+
i_exp = i_exp*10_int8 + val ; p = p + 1
410+
else
411+
exit
412+
end if
413+
end do
414+
415+
exp_aux = nwnb-1+resp-sige*i_exp
416+
if( exp_aux>0 .and. exp_aux<=nwnb+nfnb) then
417+
if(icount<=maxdpt)then
418+
v = sign*int_dp1*expbase(exp_aux)
419+
else
420+
v = sign*(int_dp1 + int_dp2*fractional_base(maxdpt-1))*expbase(exp_aux-icount+maxdpt)
421+
end if
422+
else
423+
v = sign*(int_dp1 + int_dp2*fractional_base(maxdpt-1))*10._wp**(sige*i_exp-resp+maxdpt+aux)
424+
end if
425+
stat = 0
426+
end subroutine
427+
#:endif
428+
334429
#:if WITH_QP
335430
elemental subroutine to_qp_base(s,v,p,stat)
336431
integer, parameter :: wp = qp

0 commit comments

Comments
 (0)