P3864R1 - Correctly rounded floating-point maths functions WG21
Posted by u/sg6_observer · 8 hr. ago

Authors: Guy Davidson, Jan Schultke
Document: P3864R1
Date: 2026-02-22
Target: SG6
Link: wg21.link/p3864r1

Guy Davidson and Jan Schultke propose adding five correctly rounded math functions to <cmath>: cr_add, cr_sub, cr_mul, cr_div, and cr_sqrt. These guarantee roundTiesToEven rounding regardless of the current floating-point environment state, matching what IEC 60559:2020 specifies for its basic operations.

The motivation is ergonomics. Right now, if you need a correctly rounded result, you either call fesetround() and hope nobody upstream changed the rounding mode on you, or you build an elaborate workaround with separate translation units linked at runtime. These functions let you just say what you mean. They're constexpr, noexcept, and only available for IEC 559 types.

This follows the C standard's Annex F direction, which reserves the cr_ prefix for correctly rounded functions. SG6 territory - numerics study group.

▲ 23 points (78% upvoted) · 9 comments
sorted by: best
u/fesetround_appreciator 18 points 7 hr. ago

I've been calling fesetround() like a barbarian for years. Five functions that just do the right thing without touching the floating-point environment? Sign me up.

u/just_a_cpp_dev_2024 14 points 6 hr. ago

TIL you can change the rounding mode at runtime. I've been writing C++ for 8 years and have never once thought about this.

u/fesetround_appreciator 9 points 5 hr. ago

Count yourself lucky.

u/definitely_knows_ieee754 11 points 4 hr. ago

This does not solve problem 2 directly, since this does not necessarily affect the floating-point state at all. However, it reduces the sources of error when correct rounding is important.

So it solves half of one problem and acknowledges it doesn't solve the other. Humble.

u/every_bit_counts 7 points 5 hr. ago

The C standard reserves the cr_ prefix for a lot more than five functions. Annex F lists cr_sin, cr_cos, cr_exp, cr_log, and a bunch more. This paper deliberately scopes down to just the five basic arithmetic operations - addition, subtraction, multiplication, division, square root - which are the ones IEC 60559 already requires to be correctly rounded.

the C standard in Annex F reserves the prefix cr_ for functions fully matching the mathematical operations

Fair enough as a first step, but the hard problem has always been transcendentals. CORE-MATH at INRIA has been working on correctly rounded implementations of those for years and they're making real progress getting them into glibc and LLVM libc. Is there a follow-up planned for cr_sin et al., or is this the extent of the C++ ambition here?

u/sg6_observer 4 points 4 hr. ago

I read it as intentionally minimal. The basic ops are the uncontroversial ones where correct rounding is already required by 60559. Transcendentals are a much harder standardization problem - you'd have to nail down which functions, whether the precision guarantee extends to all argument ranges, performance implications. Getting five clean functions through SG6 first seems like the right move.

u/template_wizard_99 6 points 2 hr. ago

Slightly off topic but where is P3375 (reproducible floating-point results)? That's the one I actually care about. This paper explicitly says it doesn't solve reproducibility.

u/mpfr_is_fine_actually 5 points 5 hr. ago

MPFR has provided correctly rounded arithmetic for two decades. But I suppose having it in the standard means one fewer dependency to argue about in code review.

u/constexpr_all_the_things 3 points 3 hr. ago

The interesting detail here is the constexpr marking. During constant evaluation, arithmetic already produces correctly rounded results - that's what the compiler does when there's no FP environment to fiddle with. So cr_add(x, y) at compile time is just... x + y.

The real value is runtime: if some library upstream called fesetround(FE_UPWARD) and didn't restore it, cr_add gives you the correct roundTiesToEven answer anyway. The constexpr is there for API consistency, not because you'd choose it over + in a constant expression.