Numbers
The kinds
use stringifor exports the portable kinds of PENF:
| Parameter | Type | Bytes |
|---|---|---|
I1P | integer | 1 |
I2P | integer | 2 |
I4P | integer | 4 |
I8P | integer | 8 |
R4P | real | 4 |
R8P | real | 8 |
R16P | real | 16 |
R16Pis supported (in the assignment and into_number) when the library is compiled with the-DPENF_R16Ppreprocessor flag.I2Pis not supported when the_NVFmacro is defined (NVIDIA Fortran compatibility).
Is it a number?
program number_check
!< Is it a number?
use stringifor
implicit none
type(string) :: s(6)
integer :: i
s(1) = '42' ; s(2) = '-3.14' ; s(3) = '6.02e23' ; s(4) = '1.' ; s(5) = '12 apples' ; s(6) = '007'
print '(A)', 'string number integer real digit'
do i = 1, size(s)
print '(A,4(L1,6X))', s(i)%fill(width=12, right=.true., filling_char=' ')//'', &
s(i)%is_number(), s(i)%is_integer(), s(i)%is_real(), s(i)%is_digit()
enddo
endprogram number_check$ number_check
string number integer real digit
42 T T F T
-3.14 T F T F
6.02e23 T F T F
1. T F T F
12 apples F F F F
007 T T F T| Method | True if the string is |
|---|---|
is_integer([allow_spaces]) | an integer, with an optional sign |
is_real([allow_spaces]) | a real: digits with a decimal point or an exponent (or both); an integer is not a real |
is_number([allow_spaces]) | an integer or a real |
is_digit() | made of digits only |
Leading and trailing blanks are accepted, unless allow_spaces=.false..
From a string to a number
program number_cast
!< From a string to a number.
use stringifor
implicit none
type(string) :: s
real(R8P) :: x
integer(I4P) :: n
s = '3.4e2'
if (s%is_number()) x = s%to_number(kind=1._R8P) ! the kind of the argument selects the result
print '(F0.1)', x
s = '42'
if (s%is_integer()) n = s%to_number(kind=1_I4P)
print '(I0)', n + 1
x = s%to_number(kind=1._R8P) ! an integer string is a valid real
print '(F0.1)', x
endprogram number_cast$ number_cast
340.0
43
42.0to_number(kind) returns the number in the string. The argument selects the kind of the result and nothing else: its value is ignored, pass any constant of the wanted kind (1_I4P, 1._R8P). A cast to a real kind accepts a real or an integer string, a cast to an integer kind an integer string.
A plain decimal number (a sign, at most 18 significant digits, a decimal point, an exponent) is converted without the read statement, and correctly rounded: any integer in the range of the kind, and any R4P or R8P real, by one exact operation when the digits and the power of ten are exact in the kind and by the Eisel-Lemire algorithm otherwise. About 50 ns per number with gfortran, against about 500 ns for read. R16P and strings of more digits go through read, so those results are the compiler's (ifx and nvfortran are not always correctly rounded there).
The forms of a real
program number_forms
!< The forms a real can take in a string: what Fortran writes, and the special values.
use stringifor
implicit none
type(string) :: fields(6)
real(R8P) :: value
integer :: iostat
integer :: f
fields(1) = '1.5-101' ! as E and ES edit descriptors write a 3 digit exponent
fields(2) = '1.5d3'
fields(3) = 'inf'
fields(4) = '-Infinity'
fields(5) = 'nan'
fields(6) = '2026-11' ! not a number
do f = 1, size(fields)
call fields(f)%read_number(value, iostat=iostat)
print '(A10,1X,L1,1X,ES12.4)', fields(f)%chars(), iostat == 0, value
enddo
endprogram number_forms$ number_forms
1.5-101 T 1.5000-101
1.5d3 T 1.5000E+03
inf T Infinity
-Infinity T -Infinity
nan T NaN
2026-11 F NaN- The exponent letter can be
e,E,dorD. After a decimal point it can also be missing, with a sign and exactly 3 digits:1.5-101is what the E and ES edit descriptors write for a three digit exponent.readalso takes1-2as1e-2; here it is not a number, or2026-11would be one. nan,nan(chars),infandinfinity, in any case and with a sign, are reals, foris_realandis_numbertoo.- Past the range of the kind, the result is an infinity or a zero with
iostat0.
WARNING
On a string that does not hold a suitable number the result is 0 for an integer kind and a quiet NaN for a real kind: check with is_number or is_integer first to tell a parsed 0 from a failure, or use read_number.
With an error status
program checked_cast
!< Numbers read from strings, with an error status.
use stringifor
implicit none
type(string) :: fields(3)
real(R8P) :: value
integer :: iostat
character(len=99) :: iomsg
integer :: f
fields(1) = '3.25'
fields(2) = 'n/a'
fields(3) = '1e3'
do f = 1, size(fields)
call fields(f)%read_number(value, iostat=iostat, iomsg=iomsg)
if (iostat == 0) then
print '(A,F8.2)', fields(f)//' -> ', value
else
print '(A)', fields(f)//' -> error: '//trim(iomsg)
endif
enddo
endprogram checked_cast$ checked_cast
3.25 -> 3.25
n/a -> error: the string is not a number
1e3 -> 1000.00read_number(number[, iostat][, iomsg]) is a subroutine: the kind is the one of number, and the failure is reported as by a read statement, iostat being 0 on success and positive otherwise, iomsg explaining it. On failure number gets the same value as to_number, 0 or NaN. It is elemental: on an array of strings, number and iostat are arrays.
From a number to a string
program number_to_string
!< From a number to a string.
use stringifor
implicit none
type(string) :: s
s = 42
print '(A)', s//''
s = -127_I1P
print '(A)', s//''
s = 2.5_R4P
print '(A)', s//''
s = 1._R8P/3._R8P
print '(A)', s//''
s = 255
print '(A)', s%hex()//' '//s%hex(uppercase=.true.)
s = -1
print '(A)', s%hex(bits=16)//'' ! two's complement on 16 bits
endprogram number_to_string$ number_string
+42
-127
+0.250000000E+01
+0.33333333333333331E+000
ff FF
ffffprogram shortest_text
!< A real as the shortest text that reads back as exactly that number, against the assignment.
use stringifor
implicit none
real(R8P) :: values(5)
type(string) :: full
type(string) :: short
integer :: v
values = [0.1_R8P, 100._R8P, 1.e23_R8P, 1.5e-7_R8P, -2.5_R8P]
do v = 1, size(values)
full = values(v)
short = shortest(values(v))
print '(A,1X,A)', full%chars(), short%chars()
enddo
if (short%to_number(1._R8P) == values(5)) print '(A)', 'it reads back as the same number'
endprogram shortest_text$ shortest_text
+0.10000000000000001E+000 0.1
+0.10000000000000000E+003 100.0
+0.99999999999999992E+023 1e+23
+0.14999999999999999E-006 1.5e-07
-0.25000000000000000E+001 -2.5
it reads back as the same number- An integer is written with its sign; a real with its sign and all the significant digits of its kind, so the string holds the nearest representable value. For another layout, write the number with a format into a character.
shortest(number), a module procedure forR4PandR8P, returns the shortest text that reads back as exactly that number, the closest of them if more than one, in the layout of Python'srepr. The assignment keeps its format.hex([bits][, uppercase])returns the hexadecimal representation of the integer in the string, or a string not allocated if it is not an integer. A negative number is in two's complement onbitsbits (default 64); the number is truncated to its lowestbitsbits.