cplusplus / CWG

Core Working Group
23 stars 7 forks source link

CWG2836 [conv.rank] `long double` + `_Float64` is handled differently from C #472

Closed jcranmer-intel closed 2 months ago

jcranmer-intel commented 10 months ago

Full name of submitter: Joshua Cranmer

Reference (section label): [conv.rank]

Issue description:

Suppose we have a system where double, long double, and _Float64 or std::float64_t all use the same underlying floating-point semantics. Under C23 (taken from draft N3096), the common real floating-point type is determined by first using the interchange type (i.e., _Float64), then long double, and then double). Under C++23, [conv.rank] specifies that long double and double are different ranks (per p2.2), with std::float64_t is in the same rank as double (per p2.5) and a higher subrank than double (per 3).

Under C's rules, then, if you were to add long double and _Float64, the _Float64 would be the result. But under C++, long double is the result, because the long double rank wins out over _Float64's rank. It is not clear that this result was intentional. P1467R6 and later revisions all have a C compatibility section, where these paragraphs appear:

Previously, there was also a difference in usual arithmetic conversions. This proposal and C have always agreed on the results of a binary operator when at least one of the operands is a floating-point type and the two types have different representations. However, when the two operands were different floating-point types with the same representation, this paper proposed that double + std::float64_t (assuming they have the same representation) would have type double, while in C, double + _Float64 has type _Float64. The rationale for the C rules is that if a user buys into the fixed-layout types explicitly, we should preserve that decision through expressions and library function calls.

This matter was discussed during an SG22 meeting, and a consensus was reached that this paper should instead adopt the C rules; now, with this revision, the result of double + std::float64_t is std::float64_t.

Records of the relevant SG22 meeting can be found at https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2835.pdf, which confirm that this is accurate.

A subsequent followup to the CFP mailing list by the author of P1467 was sent to ask about this case, and if C would change its rules to make long double + _Float64 yield long double instead here: http://mailman.oakapple.net/pipermail/cfp-interest/2021-October/002256.html. The CFP reply indicated no desire in C to change, and the subsequent CFP telecon also affirmed that (see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2876.pdf for meeting minutes). However, none of the further discussions of the paper in C++ appear to have observed this incompatibility with C, although the topic of mapping to double or long double was discussed during CWG telecons (specifically the one on 2022-03-25).

It is not clear if the incompatibility between C and C++ with regards to the arithmetic conversions here was intentional.

Suggested resolution: Change [conv.rank]p2.5 to

An extended floating-point type with the same set of values as more than one cv-unqualified standard floating-point type has a rank equal to the highest rank among such types.

jensmaurer commented 10 months ago

CWG2836