1
1
#:include "common.fypp"
2
2
!> The `stdlib_str2num` module provides procedures and interfaces for conversion
3
3
!> of characters to numerical types. Currently supported: `integer` and `real`.
4
- !! ([Specification](../page/specs/stdlib_str2num.html)
4
+ !> ([Specification](../page/specs/stdlib_str2num.html) )
5
5
!>
6
6
!> This code was modified from https://github.com/jalvesz/Fortran-String-to-Num by Alves Jose
7
7
!> And was possible thanks to all the discussions in this thread https://fortran-lang.discourse.group/t/faster-string-to-double/
8
8
!>
9
9
!> Known precisions limits of current proposal :
10
10
!> Conversion to double precision is exact up to epsilon(0.0_dp)
11
11
!> example:
12
+ !>
12
13
!> input : 123456.78901234567890123456789012345678901234567890+2
14
+ !>
13
15
!> formatted read : 12345678.90123457
16
+ !>
14
17
!> to_num : 12345678.90123457
18
+ !>
15
19
!> difference abs : 0.1862645149230957E-08
20
+ !>
16
21
!> difference rel : 0.1508742584455759E-13%
17
22
!>
18
23
!> Conversion to quadruple precision can deviate at about 200*epsilon(0.0_qp)
19
24
!> example:
25
+ !>
20
26
!> input : 0.140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125E-443
27
+ !>
21
28
!> formatted read : 0.140129846432481707092372958328991608E-443
29
+ !>
22
30
!> to_num : 0.140129846432481707092372958328996233E-443
31
+ !>
23
32
!> difference abs : 0.4625E-475
33
+ !>
24
34
!> difference rel : 0.3300E-029%
25
35
26
36
module stdlib_str2num
@@ -78,24 +88,24 @@ module stdlib_str2num
78
88
#:for k1, t1 in (INT_KINDS_TYPES + REAL_KINDS_TYPES)
79
89
elemental function to_${k1}$(s,mold) result(v)
80
90
! -- In/out Variables
81
- character(*), intent(in) :: s !> input string
82
- ${t1}$, intent(in) :: mold !> dummy argument to disambiguate at compile time the generic interface
83
- ${t1}$ :: v !> Output ${t1}$ value
91
+ character(*), intent(in) :: s !! input string
92
+ ${t1}$, intent(in) :: mold !! dummy argument to disambiguate at compile time the generic interface
93
+ ${t1}$ :: v !! Output ${t1}$ value
84
94
! -- Internal Variables
85
- integer(int8) :: p !> position within the number
86
- integer(int8) :: stat !> error status
95
+ integer(int8) :: p !! position within the number
96
+ integer(int8) :: stat !! error status
87
97
!----------------------------------------------
88
98
call to_num_base(s,v,p,stat)
89
99
end function
90
100
91
101
function to_${k1}$_from_stream(s,mold,stat) result(v)
92
102
! -- In/out Variables
93
- character(len=:), pointer :: s !> input string
94
- ${t1}$, intent(in) :: mold !> dummy argument to disambiguate at compile time the generic interface
95
- ${t1}$ :: v !> Output ${t1}$ value
103
+ character(len=:), pointer :: s !! input string
104
+ ${t1}$, intent(in) :: mold !! dummy argument to disambiguate at compile time the generic interface
105
+ ${t1}$ :: v !! Output ${t1}$ value
96
106
integer(int8),intent(inout), optional :: stat
97
107
! -- Internal Variables
98
- integer(int8) :: p !> position within the number
108
+ integer(int8) :: p !! position within the number
99
109
integer(int8) :: err
100
110
!----------------------------------------------
101
111
call to_num_base(s,v,p,err)
@@ -111,16 +121,16 @@ module stdlib_str2num
111
121
112
122
#:for k1, t1 in INT_KINDS_TYPES
113
123
elemental subroutine to_${k1}$_base(s,v,p,stat)
114
- !> Return an ${k1}$ integer
124
+ !! Return an ${k1}$ integer
115
125
! -- In/out Variables
116
- character(*), intent(in) :: s !> input string
117
- ${t1}$, intent(out) :: v !> Output real value
118
- integer(int8), intent(out) :: p !> position within the number
119
- integer(int8), intent(out) :: stat !> status upon succes or failure to read
126
+ character(*), intent(in) :: s !! input string
127
+ ${t1}$, intent(out) :: v !! Output real value
128
+ integer(int8), intent(out) :: p !! position within the number
129
+ integer(int8), intent(out) :: stat !! status upon succes or failure to read
120
130
! -- Internal Variables
121
131
integer(int8) :: val
122
132
!----------------------------------------------
123
- stat = 23 !> initialize error status with any number > 0
133
+ stat = 23 !! initialize error status with any number > 0
124
134
!----------------------------------------------
125
135
! Find first non white space
126
136
p = shift_to_nonwhitespace(s)
@@ -142,16 +152,16 @@ module stdlib_str2num
142
152
143
153
elemental subroutine to_sp_base(s,v,p,stat)
144
154
integer, parameter :: wp = sp
145
- !> Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
155
+ !! Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
146
156
! -- In/out Variables
147
- character(*), intent(in) :: s !> input string
148
- real(wp), intent(inout) :: v !> Output real value
149
- integer(int8), intent(out) :: p !> last position within the string
150
- integer(int8), intent(out) :: stat !> status upon success or failure to read
157
+ character(*), intent(in) :: s !! input string
158
+ real(wp), intent(inout) :: v !! Output real value
159
+ integer(int8), intent(out) :: p !! last position within the string
160
+ integer(int8), intent(out) :: stat !! status upon success or failure to read
151
161
152
162
! -- Internal Variables
153
- integer(int8), parameter :: nwnb = 39 !> number of whole number factors
154
- integer(int8), parameter :: nfnb = 37 !> number of fractional number factors
163
+ integer(int8), parameter :: nwnb = 39 !! number of whole number factors
164
+ integer(int8), parameter :: nfnb = 37 !! number of fractional number factors
155
165
integer :: e
156
166
! Notice: We use dp here to obtain exact precision for sp.
157
167
! Otherwise errors may appear in comparison to formatted read.
@@ -160,14 +170,14 @@ module stdlib_str2num
160
170
real(dp), parameter :: fractional_base(nfnb) = [(10._dp**(-e),e=1,nfnb)]
161
171
real(dp), parameter :: expbase(nwnb+nfnb) = [whole_number_base, fractional_base]
162
172
163
- integer(int8) :: sign, sige !> sign of integer number and exponential
164
- integer, parameter :: maxdpt = 11 !> Maximum depth to read values on int_wp
165
- integer(dp) :: int_wp !> long integer to capture fractional part
166
- integer :: i_exp !> integer to capture whole number part
173
+ integer(int8) :: sign, sige !! sign of integer number and exponential
174
+ integer, parameter :: maxdpt = 11 !! Maximum depth to read values on int_wp
175
+ integer(dp) :: int_wp !! long integer to capture fractional part
176
+ integer :: i_exp !! integer to capture whole number part
167
177
integer :: exp_aux
168
178
integer(int8) :: i, pP, pE, val , resp
169
179
!----------------------------------------------
170
- stat = 23 !> initialize error status with any number > 0
180
+ stat = 23 !! initialize error status with any number > 0
171
181
!----------------------------------------------
172
182
! Find first non white space
173
183
p = shift_to_nonwhitespace(s)
@@ -243,29 +253,29 @@ module stdlib_str2num
243
253
244
254
elemental subroutine to_dp_base(s,v,p,stat)
245
255
integer, parameter :: wp = dp
246
- !> Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
256
+ !! Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
247
257
! -- In/out Variables
248
- character(*), intent(in) :: s !> input string
249
- real(wp), intent(inout) :: v !> Output real value
250
- integer(int8), intent(out) :: p !> last position within the string
251
- integer(int8), intent(out) :: stat !> status upon success or failure to read
258
+ character(*), intent(in) :: s !! input string
259
+ real(wp), intent(inout) :: v !! Output real value
260
+ integer(int8), intent(out) :: p !! last position within the string
261
+ integer(int8), intent(out) :: stat !! status upon success or failure to read
252
262
253
263
! -- Internal Variables
254
- integer(int8), parameter :: nwnb = 40 !> number of whole number factors
255
- integer(int8), parameter :: nfnb = 64 !> number of fractional number factors
264
+ integer(int8), parameter :: nwnb = 40 !! number of whole number factors
265
+ integer(int8), parameter :: nfnb = 64 !! number of fractional number factors
256
266
integer :: e
257
267
real(wp), parameter :: whole_number_base(nwnb) = [(10._wp**(nwnb-e),e=1,nwnb)]
258
268
real(wp), parameter :: fractional_base(nfnb) = [(10._wp**(-e),e=1,nfnb)]
259
269
real(wp), parameter :: expbase(nwnb+nfnb) = [whole_number_base, fractional_base]
260
270
261
- integer(int8) :: sign, sige !> sign of integer number and exponential
262
- integer, parameter :: maxdpt = 19 !> Maximum depth to read values on int_wp
263
- integer(wp) :: int_wp !> long integer to capture fractional part
264
- integer :: i_exp !> integer to capture whole number part
271
+ integer(int8) :: sign, sige !! sign of integer number and exponential
272
+ integer, parameter :: maxdpt = 19 !! Maximum depth to read values on int_wp
273
+ integer(wp) :: int_wp !! long integer to capture fractional part
274
+ integer :: i_exp !! integer to capture whole number part
265
275
integer :: exp_aux
266
276
integer(int8) :: i, pP, pE, val , resp
267
277
!----------------------------------------------
268
- stat = 23 !> initialize error status with any number > 0
278
+ stat = 23 !! initialize error status with any number > 0
269
279
!----------------------------------------------
270
280
! Find first non white space
271
281
p = shift_to_nonwhitespace(s)
@@ -342,29 +352,29 @@ module stdlib_str2num
342
352
#:if WITH_XDP
343
353
elemental subroutine to_xdp_base(s,v,p,stat)
344
354
integer, parameter :: wp = xdp
345
- !> Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
355
+ !! Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
346
356
! -- In/out Variables
347
- character(*), intent(in) :: s !> input string
348
- real(wp), intent(inout) :: v !> Output real value
349
- integer(int8), intent(out) :: p !> last position within the string
350
- integer(int8), intent(out) :: stat !> status upon success or failure to read
357
+ character(*), intent(in) :: s !! input string
358
+ real(wp), intent(inout) :: v !! Output real value
359
+ integer(int8), intent(out) :: p !! last position within the string
360
+ integer(int8), intent(out) :: stat !! status upon success or failure to read
351
361
352
362
! -- Internal Variables
353
- integer(int8), parameter :: nwnb = 50 !> number of whole number factors
354
- integer(int8), parameter :: nfnb = 64 !> number of fractional number factors
363
+ integer(int8), parameter :: nwnb = 50 !! number of whole number factors
364
+ integer(int8), parameter :: nfnb = 64 !! number of fractional number factors
355
365
integer :: e
356
366
real(wp), parameter :: whole_number_base(nwnb) = [(10._wp**(nwnb-e),e=1,nwnb)]
357
367
real(wp), parameter :: fractional_base(nfnb) = [(10._wp**(-e),e=1,nfnb)]
358
368
real(wp), parameter :: expbase(nwnb+nfnb) = [whole_number_base, fractional_base]
359
369
360
- integer(int8) :: sign, sige !> sign of integer number and exponential
361
- integer, parameter :: maxdpt = 19 !> Maximum depth to read values on int_dp
362
- integer(dp) :: int_dp1, int_dp2 !> long integers to capture whole and fractional part
363
- integer :: i_exp !> integer to capture exponent number
370
+ integer(int8) :: sign, sige !! sign of integer number and exponential
371
+ integer, parameter :: maxdpt = 19 !! Maximum depth to read values on int_dp
372
+ integer(dp) :: int_dp1, int_dp2 !! long integers to capture whole and fractional part
373
+ integer :: i_exp !! integer to capture exponent number
364
374
integer :: exp_aux
365
375
integer(int8) :: i, pP, pE, val , resp, icount, aux
366
376
!----------------------------------------------
367
- stat = 23 !> initialize error status with any number > 0
377
+ stat = 23 !! initialize error status with any number > 0
368
378
!----------------------------------------------
369
379
! Find first non white space
370
380
p = shift_to_nonwhitespace(s)
@@ -455,29 +465,29 @@ module stdlib_str2num
455
465
#:if WITH_QP
456
466
elemental subroutine to_qp_base(s,v,p,stat)
457
467
integer, parameter :: wp = qp
458
- !> Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
468
+ !! Sequentially unroll the character and get the sub integers composing the whole number, fraction and exponent
459
469
! -- In/out Variables
460
- character(*), intent(in) :: s !> input string
461
- real(wp), intent(inout) :: v !> Output real value
462
- integer(int8), intent(out) :: p !> last position within the string
463
- integer(int8), intent(out) :: stat !> status upon success or failure to read
470
+ character(*), intent(in) :: s !! input string
471
+ real(wp), intent(inout) :: v !! Output real value
472
+ integer(int8), intent(out) :: p !! last position within the string
473
+ integer(int8), intent(out) :: stat !! status upon success or failure to read
464
474
465
475
! -- Internal Variables
466
- integer(int8), parameter :: nwnb = 50 !> number of whole number factors
467
- integer(int8), parameter :: nfnb = 64 !> number of fractional number factors
476
+ integer(int8), parameter :: nwnb = 50 !! number of whole number factors
477
+ integer(int8), parameter :: nfnb = 64 !! number of fractional number factors
468
478
integer :: e
469
479
real(wp), parameter :: whole_number_base(nwnb) = [(10._wp**(nwnb-e),e=1,nwnb)]
470
480
real(wp), parameter :: fractional_base(nfnb) = [(10._wp**(-e),e=1,nfnb)]
471
481
real(wp), parameter :: expbase(nwnb+nfnb) = [whole_number_base, fractional_base]
472
482
473
- integer(int8) :: sign, sige !> sign of integer number and exponential
474
- integer, parameter :: maxdpt = 19 !> Maximum depth to read values on int_dp
475
- integer(dp) :: int_dp1, int_dp2 !> long integers to capture whole and fractional part
476
- integer :: i_exp !> integer to capture exponent number
483
+ integer(int8) :: sign, sige !! sign of integer number and exponential
484
+ integer, parameter :: maxdpt = 19 !! Maximum depth to read values on int_dp
485
+ integer(dp) :: int_dp1, int_dp2 !! long integers to capture whole and fractional part
486
+ integer :: i_exp !! integer to capture exponent number
477
487
integer :: exp_aux
478
488
integer(int8) :: i, pP, pE, val , resp, icount, aux
479
489
!----------------------------------------------
480
- stat = 23 !> initialize error status with any number > 0
490
+ stat = 23 !! initialize error status with any number > 0
481
491
!----------------------------------------------
482
492
! Find first non white space
483
493
p = shift_to_nonwhitespace(s)
@@ -570,9 +580,9 @@ module stdlib_str2num
570
580
!---------------------------------------------
571
581
572
582
elemental function shift_to_nonwhitespace(s) result(p)
573
- !> move string to position of the next non white space character
574
- character(*),intent(in) :: s !> character chain
575
- integer(int8) :: p !> position
583
+ !! move string to position of the next non white space character
584
+ character(*),intent(in) :: s !! character chain
585
+ integer(int8) :: p !! position
576
586
!----------------------------------------------
577
587
p = 1
578
588
do while( p<len(s) .and. (iachar(s(p:p))==WS .or. iachar(s(p:p))==LF .or. iachar(s(p:p))==CR) )
@@ -581,9 +591,9 @@ module stdlib_str2num
581
591
end function
582
592
583
593
elemental function shift_to_whitespace(s) result(p)
584
- !> move string to position of the next white space character
585
- character(*),intent(in) :: s !> character chain
586
- integer(int8) :: p !> position
594
+ !! move string to position of the next white space character
595
+ character(*),intent(in) :: s !! character chain
596
+ integer(int8) :: p !! position
587
597
!----------------------------------------------
588
598
p = 1
589
599
do while( p<len(s) .and. .not.(iachar(s(p:p))==WS .or. iachar(s(p:p))==LF .or. iachar(s(p:p))==CR) )
0 commit comments