1+ module conversion
2+ use , intrinsic :: ieee_arithmetic, only: ieee_value, ieee_positive_inf, ieee_quiet_nan
3+ use , intrinsic :: iso_fortran_env, only: i1 = > int8, i2 = > int16, i4 = > int32, i8 = > int64, &
4+ r4 = > real32, r8 = > real64, r16 = > real128
5+ implicit none
6+ private
7+ public :: cint, cint_p
8+ public :: cdbl, cdbl_p
9+
10+ integer (kind= i2), parameter :: zero = 0_i2
11+ integer (kind= i2), parameter :: one = 1_i2
12+ integer (kind= i2), parameter :: nine = 9_i2
13+ integer (kind= i2), parameter :: digit_0 = ichar (' 0' ,kind= i2)
14+ integer (kind= i2), parameter :: period = ichar (' .' ,kind= i2) - digit_0
15+ integer (kind= i2), parameter :: comma = ichar (' ,' ,kind= i2) - digit_0
16+ integer (kind= i2), parameter :: minus_sign = ichar (' -' ,kind= i2) - digit_0
17+ integer (kind= i2), parameter :: plus_sign = ichar (' +' ,kind= i2) - digit_0
18+ integer (kind= i2), parameter :: Inf = ichar (' I' ,kind= i2)
19+ integer (kind= i2), parameter :: NaN = ichar (' N' ,kind= i2)
20+ integer (kind= i2), parameter :: le = ichar (' e' ,kind= i2) - digit_0
21+ integer (kind= i2), parameter :: BE = ichar (' E' ,kind= i2) - digit_0
22+ integer (kind= i2), parameter :: ld = ichar (' d' ,kind= i2) - digit_0
23+ integer (kind= i2), parameter :: BD = ichar (' D' ,kind= i2) - digit_0
24+ integer (kind= i2), parameter :: LF = 10 , CR = 13 , WS = 32
25+
26+ integer (kind= i2), parameter :: nwnb = 40 ! > number of whole number factors
27+ integer (kind= i2), parameter :: nfnb = 40 ! > number of fractional number factors
28+ real (r8 ), parameter :: whole_number_base(nwnb) = &
29+ [1d39 , 1d38 , 1d37 , 1d36 , 1d35 , 1d34 , 1d33 , 1d32 , &
30+ 1d31 , 1d30 , 1d29 , 1d28 , 1d27 , 1d26 , 1d25 , 1d24 , &
31+ 1d23 , 1d22 , 1d21 , 1d20 , 1d19 , 1d18 , 1d17 , 1d16 , &
32+ 1d15 , 1d14 , 1d13 , 1d12 , 1d11 , 1d10 , 1d9 , 1d8 , &
33+ 1d7 , 1d6 , 1d5 , 1d4 , 1d3 , 1d2 , 1d1 , 1d0 ]
34+ real (r8 ), parameter :: fractional_base(nfnb) = &
35+ [1d-1 , 1d-2 , 1d-3 , 1d-4 , 1d-5 , 1d-6 , 1d-7 , 1d-8 , &
36+ 1d-9 , 1d-10 , 1d-11 , 1d-12 , 1d-13 , 1d-14 , 1d-15 , 1d-16 , &
37+ 1d-17 , 1d-18 , 1d-19 , 1d-20 , 1d-21 , 1d-22 , 1d-23 , 1d-24 , &
38+ 1d-25 , 1d-26 , 1d-27 , 1d-28 , 1d-29 , 1d-30 , 1d-31 , 1d-32 , &
39+ 1d-33 , 1d-34 , 1d-35 , 1d-36 , 1d-37 , 1d-38 , 1d-39 , 1d-40 ]
40+ real (r8 ), parameter :: period_skip = 0d0
41+ real (r8 ), parameter :: expbase(nwnb+ nfnb) = [whole_number_base, fractional_base]
42+
43+ contains
44+
45+ !- --------------------------------------------
46+ ! String To Integer implementations
47+ !- --------------------------------------------
48+ elemental function cint (s ) result(int)
49+ ! -- In/out Variables
50+ character (* ), intent (in ) :: s ! > input string
51+ integer :: int ! > output integer value
52+ ! private
53+ integer (1 ) :: p ! > position within the number
54+ integer (1 ) :: stat ! error status
55+
56+ call cint32(s,int,p,stat)
57+ end function
58+
59+ function cint_p (s ,stat ) result(int)
60+ character (:), pointer :: s ! > input string
61+ integer :: int ! > output integer value
62+ integer (1 ),intent (inout ), optional :: stat
63+ ! private
64+ integer (1 ) :: p ! > position within the number
65+ integer (1 ) :: err
66+
67+ call cint32(s,int,p,err)
68+ p = min ( p , len (s) )
69+ s = > s(p:)
70+ if (present (stat)) stat = err
71+ end function
72+
73+ elemental subroutine cint32 (s ,int ,p ,stat )
74+ ! > Return an unsigned 32-bit integer
75+ ! -- In/out Variables
76+ character (* ), intent (in ) :: s ! > input string
77+ integer , intent (inout ) :: int ! > output integer value
78+ integer (1 ), intent (out ) :: p ! > position within the number
79+ integer (1 ), intent (out ) :: stat ! > status upon succes of failure to read
80+ ! private
81+ integer (1 ) :: val
82+
83+ stat = 23 ! > initialize error status with any number > 0
84+
85+ ! Find first non white space
86+ p = mvs2nwsp(s)
87+
88+ int = 0
89+ do while ( p<= len (s) )
90+ val = iachar (s(p:p))- digit_0
91+ if ( val >= 0 .and. val <= 9 ) then
92+ int = int* 10 + val ; p = p + 1
93+ else
94+ exit
95+ end if
96+ end do
97+ stat = 0
98+ end subroutine
99+
100+ !- --------------------------------------------
101+ ! String To Real function interfaces
102+ !- --------------------------------------------
103+
104+ elemental function cdbl (s ) result(r)
105+ ! -- In/out Variables
106+ character (* ), intent (in ) :: s ! > input string
107+ real (r8 ) :: r ! > Output real value
108+ ! private
109+ integer (1 ) :: p ! > position within the number
110+ integer (1 ) :: stat ! error status
111+
112+ call cdbl_dp(s,r,p,stat)
113+ end function
114+
115+ function cdbl_p (s ,stat ) result(r)
116+ ! -- In/out Variables
117+ character (:), pointer :: s ! > input string
118+ real (r8 ) :: r ! > Output real value
119+ integer (1 ),intent (inout ), optional :: stat
120+ ! private
121+ integer (1 ) :: p ! > position within the number
122+ integer (1 ) :: err
123+
124+ call cdbl_dp(s,r,p,err)
125+ p = min ( p , len (s) )
126+ s = > s(p:)
127+ if (present (stat)) stat = err
128+ end function
129+
130+ !- --------------------------------------------
131+ ! String To Real implementations
132+ !- --------------------------------------------
133+
134+ elemental subroutine cdbl_dp (s ,r ,p ,stat )
135+ ! > Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
136+ ! -- In/out Variables
137+ character (* ), intent (in ) :: s ! > input string
138+ real (r8 ), intent (inout ) :: r ! > Output real value
139+ integer (1 ), intent (out ) :: p ! > last position within the string
140+ integer (1 ), intent (out ) :: stat ! > status upon success or failure to read
141+ ! private
142+ integer (1 ) :: sign, sige ! > sign of integer number and exponential
143+ integer (r8 ) :: int_r8 ! > long integer to capture fractional part
144+ integer :: i_exp ! > integer to capture whole number part
145+ integer (1 ) :: i, pP, pE, val , resp
146+
147+ stat = 23 ! > initialize error status with any number > 0
148+
149+ ! Find first non white space
150+ p = mvs2nwsp(s)
151+
152+ ! Verify leading negative
153+ sign = 1
154+ if ( iachar (s(p:p)) == minus_sign+ digit_0 ) then
155+ sign = - 1 ; p = p + 1
156+ end if
157+ if ( iachar (s(p:p)) == Inf ) then
158+ r = sign* ieee_value(r, ieee_positive_inf); return
159+ else if ( iachar (s(p:p)) == NaN ) then
160+ r = ieee_value(r, ieee_quiet_nan); return
161+ end if
162+
163+ ! read whole and fractional number in a single integer
164+ pP = 127
165+ int_r8 = 0
166+ do i = p, min (19 + p-1 ,len (s))
167+ val = iachar (s(i:i))- digit_0
168+ if ( val >= 0 .and. val <= 9 ) then
169+ int_r8 = int_r8 * 10 + val
170+ else if ( val == period ) then
171+ pP = i
172+ else
173+ exit
174+ end if
175+ end do
176+ pE = i ! Fix the exponent position
177+ do while ( i<= len (s) )
178+ val = iachar (s(i:i))- digit_0
179+ if ( val < 0 .or. val > 9 ) exit
180+ i = i + 1
181+ end do
182+ p = i
183+ resp = pE- min (pP,p) ! If no decimal indicator found it is taken as being in the current p position
184+ if ( resp <= 0 ) resp = resp+1
185+
186+ ! Get exponential
187+ sige = 1
188+ if ( p< len (s) ) then
189+ if ( any ([le,BE,ld,BD]+ digit_0== iachar (s(p:p))) ) p = p + 1
190+ if ( iachar (s(p:p)) == minus_sign+ digit_0 ) then
191+ sige = - 1
192+ p = p + 1
193+ else if ( iachar (s(p:p)) == plus_sign+ digit_0 ) then
194+ p = p + 1
195+ end if
196+ end if
197+
198+ i_exp = 0
199+ do while ( p<= len (s) )
200+ val = iachar (s(p:p))- digit_0
201+ if ( val >= 0 .and. val <= 9 ) then
202+ i_exp = i_exp* 10_i2 + val ; p = p + 1
203+ else
204+ exit
205+ end if
206+ end do
207+
208+ r = sign* int_r8 * expbase(nwnb-1 + resp- sige* max (0 ,i_exp))
209+ stat = 0
210+ end subroutine
211+
212+ !- --------------------------------------------
213+ ! Utility functions
214+ !- --------------------------------------------
215+
216+ elemental function mvs2nwsp (s ) result(p)
217+ ! > get position of the next non white space character
218+ character (* ),intent (in ) :: s ! > character chain
219+ integer (1 ) :: p ! > position
220+
221+ p = 1
222+ do while ( p< len (s) .and. (iachar (s(p:p))==WS.or. iachar (s(p:p))==LF.or. iachar (s(p:p))==CR) )
223+ p = p + 1
224+ end do
225+ end function
226+
227+ elemental function mvs2wsp (s ) result(p)
228+ ! > get position of the next white space character
229+ character (* ),intent (in ) :: s ! > character chain
230+ integer (1 ) :: p ! > position
231+
232+ p = 1
233+ do while ( p< len (s) .and. .not. (iachar (s(p:p))==WS.or. iachar (s(p:p))==LF.or. iachar (s(p:p))==CR) )
234+ p = p + 1
235+ end do
236+ end function
237+ end module
0 commit comments