This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
4101. LWG 117 loses the sign for negative NaN on some architecturesSection: 31.7.6.3.2 [ostream.inserters.arithmetic] Status: New Submitter: Jonathan Wakely Opened: 2024-05-10 Last modified: 2024-05-15
Priority: 3
View all other issues in [ostream.inserters.arithmetic].
View all issues with New status.
Discussion:
LWG 117(i) 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?
Previous resolution [SUPERSEDED]:
This wording is relative to N4981.
Modify 31.7.6.3.2 [ostream.inserters.arithmetic] as indicated:
-3- Whenval
is of typefloat
the formatting conversion occurs as if it performed the following code fragment:[Note ?: Whenbool failed = use_facet< num_put<charT, ostreambuf_iterator<charT, traits>> >(getloc()).put(*this, *this, fill(), static_cast<double>(val)).failed();
val
is a NaN value, the conversion todouble
can alter the sign and payload. — end note]
[2024-05-15; Reflector poll]
Set priority to 3 after reflector poll.
[2024-05-15; Peter Dimov provides improved wording]
Jonathan observes that the same problem exists for operator<<(extended-floating-point-type)
.
Proposed resolution:
This wording is relative to N4981.
Modify 31.7.6.3.2 [ostream.inserters.arithmetic] as indicated:
-3- Whenval
is of typefloat
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
isval
converted to typedouble
as if bystatic_cast<double>(val)
, except that the sign and payload of NaN values may be preserved rather than discarded.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4