Created on 2024-05-10.00:00:00 last changed 6 months ago
Proposed resolution:
This wording is relative to N4981.
Modify [ostream.inserters.arithmetic] as indicated:
-3- When `val` is of type `float` the formatting conversion occurs as if it performed the following code fragment:wherebool failed = use_facet< num_put<charT, ostreambuf_iterator<charT, traits>> >(getloc()).put(*this, *this, fill(),
static_cast<double>(val)dval).failed();dval
is `val` converted to type `double` as if bystatic_cast<double>(val)
, except that the sign and payload of NaN values may be preserved rather than discarded.
[ 2024-05-15; Peter Dimov provides improved wording ]
Jonathan observes that the same problem exists for
operator<<(extended-floating-point-type)
.
[ 2024-05-15; Reflector poll ]
Set priority to 3 after reflector poll.
LWG 117 fixed insertion of a `float` into an ostream by
requiring a cast to `double`. This gives a surprising result on RISC-V when
inserting a negative NaN, because RISC-V floating-point instructions do
not preserve the sign or payload of NaN values. This means that
std::cout << -std::numeric_limits<float>::quiet_NaN()
prints `"nan"` rather than `"-nan"` as most users probably expect.
11.3 section of the RISC-V ISA manual (20191213):
Except when otherwise stated, if the result of a floating-point operation is NaN, it is the canonical NaN. The canonical NaN has a positive sign and all significand bits clear except the MSB, a.k.a. the quiet bit. For single-precision floating-point, this corresponds to the pattern 0x7fc00000.
This is allowed by IEEE 754 (2019), as per section 6.3:
When either an input or result is a NaN, this standard does not interpret the sign of a NaN.
So it is standard-conforming for static_cast<double>(val)
to lose the sign (and payload) of a NaN.
This might also affect Apple M1 chips, if they use the ARMv8 default-NaN mode.
The current wording does not permit an implementation to use something like
std::copysign(static_cast<double>(val), std::signbit(val) ? -1.0 : +1.0)
to restore the sign bit. Should this be allowed? Maybe we should say that it's
unspecified whether the cast to `double` preserves the sign of a NaN?
If not, should we add a note about the surprising behaviour?
This wording is relative to N4981.
Modify [ostream.inserters.arithmetic] as indicated:
-3- When `val` is of type `float` the formatting conversion occurs as if it performed the following code fragment:[Note ?: When `val` is a NaN value, the conversion to `double` can alter the sign and payload. — end note]bool failed = use_facet< num_put<charT, ostreambuf_iterator<charT, traits>> >(getloc()).put(*this, *this, fill(), static_cast<double>(val)).failed();
History | |||
---|---|---|---|
Date | User | Action | Args |
2024-05-15 10:12:25 | admin | set | messages: + msg14145 |
2024-05-15 10:12:25 | admin | set | messages: + msg14144 |
2024-05-13 13:33:51 | admin | set | messages: + msg14141 |
2024-05-10 00:00:00 | admin | create |