Deterministic, compiler independent formatting of reals and integers.
Not even an internal write with a fully explicit edit descriptor is used
for reals, because two things remain processor dependent even then:
ROUND= defaults
to PROCESSOR_DEFINED, and the ROUND= specifier itself is not
uniformly supported), andFw.d output of a
magnitude below one (0.25 versus .25).Instead the exact decimal expansion of the IEEE value is generated here
with integer arithmetic only, and then rounded explicitly. Integers are
delegated to to_string from pic_strings, whose no-format integer path
is already a hand rolled digit by digit conversion that accumulates in
negative space so that -huge()-1 converts without overflow.
Reals are rounded round half to even against the exact binary value of
the argument, not against the decimal literal that was written in the
source. This is the only rounding rule that can be reproduced exactly, and
it is occasionally surprising: 0.15_dp is really
0.1499999999999999944..., so to_string_fixed(0.15_dp, 1) is "0.1",
not "0.2". A tie is only a tie when the binary value is exactly halfway,
which happens only for dyadic rationals such as 0.25 or 2.5.
Canonical spellings, identical on every compiler and in every routine:
NaN of any payload or sign renders as NaN, positive infinity as Inf
and negative infinity as -Inf.
The sign of a non-zero argument is always preserved, including for values
that round to zero: to_string_fixed(-1.0e-9_dp, 2) is "-0.00".
Zero is always rendered without a sign, so to_string_fixed(-0.0_dp, 2)
is "0.00", not "-0.00". Distinguishing the signed zeros is processor
dependent in Fortran (F2018 16.9.165 makes SIGN return |A| where the
processor cannot tell them apart) and Intel and AOCC do not tell them
apart under their default floating point model. Rendering a sign here
would make the output depend on the compiler and its flags, which is
exactly what this module exists to prevent, so negative zero is
canonicalised to positive zero instead. This matches pic_array_hash,
which collapses the signed zeros to one digest for the same reason.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| character(len=*), | public, | parameter | :: | PIC_FORMAT_INF | = | "Inf" |
Canonical rendering of positive infinity. |
| integer(kind=default_int), | public, | parameter | :: | PIC_FORMAT_MAX_DECIMALS | = | 200_default_int |
Largest number of decimals honoured by |
| integer(kind=default_int), | public, | parameter | :: | PIC_FORMAT_MAX_SIG_DIGITS | = | 40_default_int |
Largest number of significant digits honoured by |
| character(len=*), | public, | parameter | :: | PIC_FORMAT_NAN | = | "NaN" |
Canonical rendering of a not a number value. |
| character(len=*), | public, | parameter | :: | PIC_FORMAT_NEG_INF | = | "-Inf" |
Canonical rendering of negative infinity. |
| character(len=*), | private, | parameter | :: | ALL_DIGITS | = | "0123456789" |
Digit lookup table, mirroring the table driven integer conversion in
|
| integer(kind=int64), | private, | parameter | :: | LIMB_BASE | = | 1000000000_int64 |
Radix of the big integer scratch representation. Fixed width |
| integer(kind=default_int), | private, | parameter | :: | LIMB_DIGITS | = | 9_default_int |
Decimal digits carried in one big integer limb. |
| integer(kind=default_int), | private, | parameter | :: | MAX_DIGITS | = | MAX_LIMBS*LIMB_DIGITS |
Decimal digit capacity of the scratch big integer. |
| integer(kind=default_int), | private, | parameter | :: | MAX_LIMBS | = | 100_default_int |
Limb capacity. The widest intermediate is |
| character(len=*), | private, | parameter | :: | ODD_DIGITS | = | "13579" |
Used to test the parity of the last retained digit for half to even. |
| integer(kind=default_int), | private, | parameter | :: | WORK_LEN | = | MAX_DIGITS+PIC_FORMAT_MAX_DECIMALS+2_default_int |
Length of the digit string scratch buffers. |
Render a real in fixed point notation with an exact number of decimals. Fixed point rendering, never an exponent.
The result carries exactly decimals digits after the decimal point,
correctly rounded round half to even from the exact binary value. A
leading 0 is always written for magnitudes below one, and decimals
equal to zero produces no trailing decimal point. decimals is clamped
to the range [0, PIC_FORMAT_MAX_DECIMALS].
Fixed point rendering of a real(sp) value.
Widening to real(dp) is exact for every finite real(sp) value and
preserves NaN and both infinities, so the double precision expansion
produces the same digits.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=sp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | decimals |
Fixed point rendering of a real(dp) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | decimals |
Render a real in scientific notation with a canonical exponent field.
Scientific rendering, canonical form [-]D[.DDD]e[+-]NN.
Exactly sig_digits significant digits are produced, one before the
decimal point and the rest after it; sig_digits equal to one yields
no decimal point. The exponent letter is always a lowercase e, the
exponent sign is always present, and the exponent magnitude is written
with a minimum of two digits, zero padded on the left (three digits are
used when the magnitude requires them, as for 1.0e-300). Zero is
rendered with an exponent of zero. sig_digits is clamped to the range
[1, PIC_FORMAT_MAX_SIG_DIGITS].
Scientific rendering of a real(sp) value. See to_string_fixed_sp
for why the widening to real(dp) is lossless.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=sp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | sig_digits |
Scientific rendering of a real(dp) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | sig_digits |
Render an integer right aligned in a field of the requested width. Right aligned integer rendering, blank padded on the left.
The value is never truncated and never replaced by asterisks: if it
does not fit in width characters the field is widened and the full
number is returned, so the result length is max(width, needed). A
width of zero or less simply returns the unpadded number.
Right aligned rendering of an integer(int32) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int32), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | width |
Right aligned rendering of an integer(int64) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | width |
Place the decimal point in an already rounded digit string.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| logical, | intent(in) | :: | negative | |||
| character(len=*), | intent(in) | :: | rounded | |||
| integer(kind=default_int), | intent(in) | :: | n_rounded | |||
| integer(kind=default_int), | intent(in) | :: | point_pos | |||
| integer(kind=default_int), | intent(in) | :: | dec |
Canonical exponent field: sign, then at least two zero padded digits.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=default_int), | intent(in) | :: | exp10 |
True for negative values. The result for negative zero is processor
dependent, so callers must not rely on it: every caller here tests
value == 0 first and drops the sign for zero. Not valid for NaN,
which the callers have already filtered out.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | value |
Blank pad on the left, widening rather than truncating.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | text | |||
| integer(kind=default_int), | intent(in) | :: | width |
Fixed point rendering of a real(dp) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | decimals |
Fixed point rendering of a real(sp) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=sp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | decimals |
Scientific rendering of a real(dp) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | sig_digits |
Scientific rendering of a real(sp) value. See to_string_fixed_sp
for why the widening to real(dp) is lossless.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=sp), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | sig_digits |
Right aligned rendering of an integer(int32) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int32), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | width |
Right aligned rendering of an integer(int64) value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | value | |||
| integer(kind=default_int), | intent(in) | :: | width |
Multiply the big integer in place by base**power.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(inout) | :: | limb(:) | |||
| integer(kind=default_int), | intent(inout) | :: | n_limb | |||
| integer(kind=int64), | intent(in) | :: | base | |||
| integer(kind=default_int), | intent(in) | :: | power |
Multiply the big integer in place by a factor smaller than LIMB_BASE.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(inout) | :: | limb(:) | |||
| integer(kind=default_int), | intent(inout) | :: | n_limb | |||
| integer(kind=int64), | intent(in) | :: | factor |
Initialise the big integer from a strictly positive int64.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(out) | :: | limb(:) | |||
| integer(kind=default_int), | intent(out) | :: | n_limb | |||
| integer(kind=int64), | intent(in) | :: | value |
Write the big integer out as a decimal digit string, no leading zeros.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | limb(:) | |||
| integer(kind=default_int), | intent(in) | :: | n_limb | |||
| character(len=*), | intent(out) | :: | exact | |||
| integer(kind=default_int), | intent(out) | :: | n_exact |
Exact decimal expansion of a finite, strictly positive value.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | value | |||
| character(len=*), | intent(out) | :: | exact | |||
| integer(kind=default_int), | intent(out) | :: | n_exact | |||
| integer(kind=default_int), | intent(out) | :: | point_pos |
Add one to a decimal digit string, growing it on carry out.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(inout) | :: | rounded | |||
| integer(kind=default_int), | intent(inout) | :: | n_rounded | |||
| integer(kind=default_int), | intent(out) | :: | bump |
Expand one limb into exactly LIMB_DIGITS zero padded characters,
table driven the same way pic_strings converts integers.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer(kind=int64), | intent(in) | :: | value | |||
| character(len=*), | intent(out) | :: | chunk |
Round an exact digit string to n_keep leading digits, half to even.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | exact | |||
| integer(kind=default_int), | intent(in) | :: | n_exact | |||
| integer(kind=default_int), | intent(in) | :: | n_keep | |||
| character(len=*), | intent(out) | :: | rounded | |||
| integer(kind=default_int), | intent(out) | :: | n_rounded | |||
| integer(kind=default_int), | intent(out) | :: | bump |
Detect NaN and the infinities and return their canonical spelling.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | value | |||
| character(len=:), | intent(out), | allocatable | :: | string | ||
| logical, | intent(out) | :: | special |