C++ Logo

std-proposals

Advanced search

Re: [std-proposals] [isocpp-sci] P3935R0 Rebasing <cmath> on C23

From: Joshua Cranmer <joshua.cranmer_at_[hidden]>
Date: Tue, 2 Dec 2025 14:53:53 -0500
On 11/25/2025 3:18, Jan Schultke via Sci wrote:
> https://isocpp.org/files/papers/D3935R0.html
>
> Just wanted to let you know that I've begun work on the inevitable
> rebase of C++29's <cmath> on C23.
>
> If anyone wants to help with the effort or champion it, let me know.
>
First off, it's great that somebody's working on this!

With regards to "narrow rounding functions": the purpose of these
functions, AIUI, is to implement the requirement in IEEE 754 that the
basic arithmetic operations be fully heterogeneous for all
floating-point types of the same radix, so that you need something to
implement [e.g.] add(double, long double) -> float without any
intermediate rounding. The implementation is generally going to be
"promote all the operands to a type large enough to a) represent all of
the source operands exactly and b) not induce double rounding when
truncating the result to the output" (with some trickery when such a
type doesn't exist, e.g., `add(binary80, binary80) -> binary64` as
binary80 isn't sufficiently larger than binary64 to avoid double rounding).

Given that, it's probably a lot more ergonomic in C++ to implement it as
a function template.

Note that for the function template version, there needs to be a
constraint that the floating-point types all have the same radix (i.e.,
you can't do template <> std::decimal32_t fadd(double, double)).

With regards to "iscanonical": I find the examples used for noncanonical
values as being a poor guide, especially because most of them allude to
fast-math decisions in the compiler, and a function like `iscanonical`
is going to return the same value independent of the fast-math flags in
effect.

Among architectures in notable use today, the main examples of
noncanonical values are going to be in the decimal floating-point types.
The long double types on x86 and PPC are an 80-bit type and a
double-double type which both contain several categories of "invalid"
values which is somewhat unclear how to handle. For the 80-bit type, the
"pseudo-denormal" category (exponent field all 0's, but integer bit set)
is treated as a valid value and thus it is strongly arguable that they
are noncanonical versions of the smallest normal numbers they act as,
while the other kinds of invalid value all trigger the INVALID exception
and generally acts as an sNaN value would. The PPC long double type is a
double-double type, which has several categories of invalid values, but
I'm not very well-versed about the particulars of this type.

 From my reading of C23, a "non-canonical representation" need not have
a corresponding canonical representation. It seems pretty clear to me
that the invalid values for x86 and PPC long double must definitely
return false for `iscanonical(x)`. Note that `canonicalize` is not
required to canonicalize a value; a more C++-y interface for this method
would be `std::optional<T> canonicalize(T value)`, but that's probably a
step too far for <cmath>.

Received on 2025-12-02 19:54:07