---
title: "Rebasing<cmath>on C23"
document: P3935R1
date: 2026-05-11
audience: SG22
reply-to:
  - "Jan Schultke < <janschultke@gmail.com>"
paper-type: proposal
---

Most of C++26 is based on C23, but the header `<cmath>` is still based on C17. There are many useful C23 `<math.h>` features that should be provided in C++.



### Changes since R0

## Introduction

[[P3348R4]](https://wg21%2elink/p3348r4) rebased the C++26 standard on C23; it previously referred to C17. However, this process was deliberately left incomplete: some of the new C23 `<math.h>` features are only used by decimal floating-point types, or they require core language changes, etc.

The goal of this proposal is to pull in all the new C23 `<math.h>` features which are useful not only to decimal floating-point numbers.

Introducing decimal floating-point numbers into C++ is out-of scope. That is, adding C's `_Decimal128` type as a `std::decimal128_t` alias is not proposed. However, this proposal lays a bit of groundwork to make that happen in the future, such as introducing the concept of canonical representations into the core language.

`<simd>` is also out-of-scope, but expanding `<simd>` support for these new functions should be done in a future paper.

## Design

### New functions

The functions in the table below are proposed for inclusion in C++29. The placeholder `*F*` is a shorthand for the `*floating-point-type*` placeholder in [[cmath.syn]](https://eel.is/c++draft/cmath.syn). In addition to the functions using an `*F*` placeholder, single-type functions such as `float acospif(float)` are proposed, but are not listed in the table for the sake of brevity; refer to §5. Wording for the complete list.

| Function | ISO/IEC 60559 op. | Returns |
| --- | --- | --- |
| `bool iscanonical(*F* x);` | isCanonical | `true` if and only if `x` is canonical |
| `bool issignaling(*F* x);` | isSignaling | `true` if and only if `x` is a signaling NaN |
| `bool issubnormal(*F* x);` | isSubnormal | `true` if and only if `x` is subnormal |
| `bool iszero(*F* x);` | isZero | `true` if and only if `x` is zero |
| `*F* acospi(*F* x);` | acosPi | arccos(x)
÷
π

      in the interval [
0,1
] |
| `*F* asinpi(*F* x);` | asinPi | arcsin(x)
÷
π

      in the interval 
[
−12,
+12] |
| `*F* atanpi(*F* x);` | atanPi | arctan(x)
÷
π

      in the interval [
−12,
+12
] |
| `*F* atan2pi(*F* y, *F* x);` | atan2Pi | atan2(x,y)
÷
π

      in the interval [
−1,
+1
] |
| `*F* cospi(*F* x);` | cosPi | cos(
x×π
) |
| `*F* sinpi(*F* x);` | sinPi | sin(
x×π
) |
| `*F* tanpi(*F* x);` | tanPi | tan(
x×π
) |
| `*F* exp10(*F* x);` | exp10 | 10x |
| `*F* exp10m1(*F* x);` | exp10m1 | 10x
−
1 |
| `*F* exp2m1(*F* x);` | exp2m1 | 2x
−
1 |
| `*F* log10p1(*F* x);` | log10p1 | log10
(
1+x
) |
| `*F* logp1(*F* x);` | logp1 | log(
1+x
) |
| `*F* log2p1(*F* x);` | log2p1 | log2
(
1+x
) |
| `*F* compoundn(*F* x,
long long n);` | compound | (
1+x
)

n |
| `*F* pown(*F* x, long long n);` | pown | x
n |
| `*F* powr(*F* y, *F* x);` | powr | e

y
loge
x |
| `*F* rootn(*F* x, long long n);` | rootn | x
1n |
| `*F* rsqrt(*F* x);` | rSqrt | 1
x |
| `*F* roundeven(*F* x);` | roundToIntegralTiesToEven | `x` rounded to the nearest integer,

      rounding halfway cases to even |
| `*F* fromfp(*F* x, int rnd,
unsigned width);` | convertToInteger… | `x` rounded to a signed `width`-bit integer,

      or NaN if `x` is not in range;

`rnd` is the rounding mode |
| `*F* ufromfp(*F* x, int rnd,
unsigned width);` | convertToInteger… | `x` rounded to an unsigned `width`-bit integer,

      or NaN if `x` is not in range;

`rnd` is the rounding mode |
| `*F* fromfpx(*F* x, int rnd,
unsigned width);` | convertToIntegerExact… | `fromfp(x, rnd, width)`;

      may also raise FE_INEXACT |
| `*F* ufromfpx(*F* x, int rnd,
unsigned width);` | convertToIntegerExact… | `ufromfp(x, rnd, width)`;

      may also raise FE_INEXACT |
| `int canonicalize(
*F** cx, const *F** x);` | convertFormat (same format) | zero if canonicalization succeeded,

      and nonzero value otherwise |
| `*F* fmaximum_mag(*F* x, *F* y);` | maximumMagnitude | the value with greater magnitude,

      or `fmaximum(x, y)` |
| `*F* fminimum_mag(*F* x, *F* y);` | minimumMagnitude | the value with greater magnitude,

      or `fminimum(x, y)` |
| `*F* fmaximum_mag_num(*F* x, *F* y);` | maximumMagnitudeNumber | the value with greater magnitude,

      or `fmaximum_num(x, y)` |
| `*F* fminimum_mag_num(*F* x, *F* y);` | minimumMagnitudeNumber | the value with greater magnitude,

      or `fminimum_num(x, y)` |
| `float fadd(*F* x, *F* y);
double dadd(*F* x, *F* y);` | addition | x+y |
| `float fsub(*F* x, *F* y);
double dsub(*F* x, *F* y);` | subtraction | x−y |
| `float fmul(*F* x, *F* y);
double dmul(*F* x, *F* y);` | multiplication | x×y |
| `float fdiv(*F* x, *F* y);
double ddiv(*F* x, *F* y);` | division | x÷y |
| `float ffma(*F* x, *F* y, *F* z);
double dfma(*F* x, *F* y, *F* z);` | fusedMultiplyAdd | (x×y)
+z |
| `float fsqrt(*F* x);
double dsqrt(*F* x);` | squareRoot | x |
| `bool iseqsig(*F* x, *F* y)` | compareSignalingEqual | `true` if `x` and `y` are equal and

`false` otherwise |
| `bool totalorder(
const *F** x,
const *F** y);` | totalOrder | `true` if totalOrder(`*x`, `*y`)
      is true,

      as per ISO/IEC 60559 |
| `bool totalordermag(
const *F** x,
const *F** y);` | totalOrderMag | `true` if totalOrderMag(`*x`, `*y`)
      is true,

      as per ISO/IEC 60559 |
| `*F* getpayload(const *F** x);` | getPayload | the NaN payload in `*x`,

      or -1 if the `*x` is not a NaN |
| `int setpayload(
*F** res, *F* pl);` | setPayload | zero if the NaN payload in `*res` could be set,

      and nonzero value otherwise |
| `int setpayloadsig(
*F** res, *F* pl);` | setPayloadSig | same as `setpayload`,

      but creates sNaN instead of qNan |

As can be seen, all of these implement an ISO/IEC 60559 operation, and even if they didn't, they would be useful solely for the purpose of C compatibility.

All functions below `iseqsig` are specific to ISO/IEC 60559, and are only provided by C23 for types that adhere to ISO/IEC 60559. The same restriction should be inherited by C++; otherwise e.g. `totalorder` would require us to define a total order for every possible format of floating-point type, which seems unreasonable.

All new functions should be `constexpr` because none of them have a strong dependence on the current rounding mode or floating-point environment.

#### No SIMD support

At this time, no SIMD overloads are proposed because

- it would significantly broaden the scope of this proposal beyond just establishing C23 compatibility,
- the function signatures are not obvious in many cases (would `fromfp` take a `basic_vec` of rounding modes?), and
- there is no particular urgency to do it all in one paper; it does not result in a broken specification, just in some missing nice-to-have features for `<simd>`.

#### Narrow rounding functions

The narrow rounding functions (such as `fadd`) are unusually difficult to expose in C++ in a generic way. Even the `<tgmath.h>` versions require the user to specify the return type as a prefix (f, d, f32, …) as part of the function name. This is extremely hostile to generic code, and also means there is no support for extended floating-types in C++ because we don't consider `std::float32_t` to be C23's `_Float32` and to have `sqrtf32` and other functions that accept it.

To solve this, we can do something novel: add function templates for these rounding functions:

template

<

class

T

,

class

F1

,

class

F2

>

constexpr

T

fadd

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

,

class

F2

>

constexpr

T

fsub

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

,

class

F2

>

constexpr

T

fmul

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

,

class

F2

>

constexpr

T

fdiv

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

,

class

F2

,

class

F3

>

constexpr

T

ffma

(

F1

x

,

F2

y

,

F3

z

)

;

template

<

class

T

,

class

F1

>

constexpr

T

fsqrt

(

F1

x

)

;

While the prefix f is a bit inappropriate (it it supposed to indicate a `float` return type), there is no obvious alternative prefix, f definitely won't clash with future `<math.h>` functions, and having no prefix at all would create undesirable overload sets with other functions.

The design goal for these functions is for the user to be able to write:

#ifdef __cplusplus

#define f32add(...)

::

std

::

fadd

<

std

::

float32_t

>

(

__VA_ARGS__

)

//

...

#else

#include <tgmath.h>

#endif

There is also a non-template `std::fadd` function which is meant to emulate the behavior of the `<tgmath.h>` macro by selecting between the `long double`→`float` and `double`→`float` overloads.

These templates are not `noexcept` because they dispatch to underlying C functions that are not `noexcept`. We also traditionally don't make new C++ overloads of C functions `noexcept`, such as in the case of the three-parameter `std::lerp` overload. Despite that, they are not intended to throw.

#### Canonical floating-point representations and canonicalization

C23 introduced the concept of "canonical representations" identified by `iscanonical`, and a function `canonicalize` to convert to canonical representations of the same value.

Examples of canonical/non-canonical representations include:

- Representations for decimal floating-point types are specified to be canonical or non-canonical by ISO/IEC 60559.
- Signaling NaN may be non-canonical, whereas quiet NaN may be canonical.
- An implementation that flushes subnormals to zero may consider all subnormal normals to be non-canonical representations of zero.
- Negative zero may be considered a non-canonical representation of positive zero, which is canonical.

Unless working with decimal floating-point types, the classification of representations as "canonical" is largely based on the subjective preferences of the implementation; there are no hard rules other than a canonical representation being unique.

### New macros

Besides the new functions, there are also macros which are pulled in from C23.

The `int rnd` parameter in functions such as `fromfp` corresponds to one of FP_INT_* rounding direction macros.

The block below lists all new macros (not yet including the `float*N*_t` placeholder versions):

//

rounding direction macros

FP_INT_UPWARD

FP_INT_DOWNWARD

FP_INT_TOWARDZERO

FP_INT_TONEARESTFROMZERO

FP_INT_TONEAREST

//

indicates that the respective function is "fast"

FP_FAST_FADD

FP_FAST_FADDL

FP_FAST_DADDL

FP_FAST_FSUB

FP_FAST_FSUBL

FP_FAST_DSUBL

FP_FAST_FMUL

FP_FAST_FMULL

FP_FAST_DMULL

FP_FAST_FDIV

FP_FAST_FDIVL

FP_FAST_DDIVL

FP_FAST_FSQRT

FP_FAST_FSQRTL

FP_FAST_DSQRTL

FP_FAST_FFMA

FP_FAST_FFMAL

FP_FAST_DFMAL

### New declarations for float*N*_t

C23 also provides a suffixed version of all the common common mathematical functions with `f*N*` suffix and with `float*N*_t` parameters. While these are not particularly useful considering that the user can (and probably should) call the overloaded functions, the current design direction is for C++ to inherit suffixed functions; we already do so for `sqrtf` and `sqrtl`. It would make porting C code to C++ and vice versa needlessly difficult if the suffixed functions only existed in one standard, for seemingly no technical reason.

In the case of the narrow rounding functions, C23 also has

- prefixed generic functions such as `f32add`, and
- prefixed concrete functions such as `f32addf64`,

as explained above.

The pattern of always providing the suffixed versions is only broken by `fminimum`, `fminimum_num`, `fmaximum`, and `fmaximum_num`. These functions were added to C++26 by [[P3008R6]](https://wg21%2elink/p3008r6), mostly to specify the behavior of atomic floating-point minimum/maximum in terms of the C23 functions. There is no technical reason why the suffixed versions shouldn't also be provided, and the paper does not discuss this option.

## Implementation experience

All non-template additions are taken from C23, and most have been implemented in gnulibc.

The new narrow rounding function templates simply dispatch to some non-template overload based on the template argument `T`.

## Wording

The changes are relative to [[N5014]](https://wg21%2elink/n5014).

### [basic.fundamental]

Immediately prior to [[basic.fundamental] paragraph 13](https://eel.is/c++draft/basic.fundamental#13), insert a new paragraph:

An implementation may prefer particular representations of values that have multiple representations in a floating-point type. The preferred representations of a floating-point type, including unique representations of values in the type, are called canonical. A floating-point type may also contain non-canonical representations, for example, redundant representations of some or all its values, or representations that are extraneous to the floating-point model. Typically, floating-point operations deliver results with canonical representations.

[*Note*: The functions `std::iscanonical` and `std::canonicalize` distinguish canonical (preferred) representations, but this distinction alone does not imply that canonical and non-canonical representations are of different values. — *end note*]

The C23 wording is extremely vague, and we can't be precise either if we don't want to risk having diverging behavior for `iscanonical`.

`iscanonical` and `canonicalize` are primarily motivated by ISO/IEC 60559 decimal floating-point representations anyway, where it is precisely specified which representations are canonical.

### [version.syn]

Add a feature-test macro to [[version.syn]](https://eel.is/c++draft/version.syn) as follows:

#define __cpp_lib_cmath 20XXXXL

//

also in

<cmath>

,

<cstdlib>

Although the proposal also adds a `__STDC_VERSION_MATH_H__` macro from C23, this cannot be reliably used to detect the new functions; it could have also been leaked through a `<math.h>` header from somewhere, without e.g. `std::roundeven` actually existing.

Bump the feature-test macro for mathematical special functions:

#define __cpp_lib_math_special_functions

201603L

20XXXXL

//

also in

<cmath>

This queries existence of new overloads such as `ellint_3f32`.

### [cmath.syn]

#define __STDC_VERSION_MATH_H__ 202311L


#define HUGE_VAL

see below

#define HUGE_VALF

see below

#define HUGE_VALL

see below

#define HUGE_VAL_F*N* *see below* // optional

#define INFINITY

see below

#define NAN

see below

#define FP_INFINITE

see below

#define FP_NAN

see below

#define FP_NORMAL

see below

#define FP_SUBNORMAL

see below

#define FP_ZERO

see below


#define FP_INT_UPWARD *see below*
#define FP_INT_DOWNWARD *see below*
#define FP_INT_TOWARDZERO *see below*
#define FP_INT_TONEARESTFROMZERO *see below*
#define FP_INT_TONEAREST *see below*


#define FP_FAST_FMA

see below

#define FP_FAST_FMAF

see below

#define FP_FAST_FMAL

see below

#define FP_FAST_FMAF*N* *see below*
#define FP_FAST_FADD *see below*
#define FP_FAST_FADDL *see below*
#define FP_FAST_DADDL *see below*
#define FP_FAST_F*M*ADD*N* *see below*
#define FP_FAST_FSUB *see below*
#define FP_FAST_FSUBL *see below*
#define FP_FAST_DSUBL *see below*
#define FP_FAST_F*M*SUB*N* *see below*
#define FP_FAST_FMUL *see below*
#define FP_FAST_FMULL *see below*
#define FP_FAST_DMULL *see below*
#define FP_FAST_F*M*MUL*N* *see below*
#define FP_FAST_FDIV *see below*
#define FP_FAST_FDIVL *see below*
#define FP_FAST_DDIVL *see below*
#define FP_FAST_F*M*DIV*N* *see below*
#define FP_FAST_FSQRT *see below*
#define FP_FAST_FSQRTL *see below*
#define FP_FAST_DSQRTL *see below*
#define FP_FAST_F*M*SQRT*N* *see below*
#define FP_FAST_FFMA *see below*
#define FP_FAST_FFMAL *see below*
#define FP_FAST_DFMAL *see below*
#define FP_FAST_F*M*FMA*N* *see below*


#define FP_ILOGB0

see below

#define FP_ILOGBNAN

see below

#define MATH_ERRNO

see below

#define MATH_ERREXCEPT

see below

#define math_errhandling

see below

namespace

std

{

using

float_t

=

see below

;

using

double_t

=

see below

;

 using long_double_t = *see below*;

constexpr

floating-point-type

acos

(

floating-point-type

x

)

;

constexpr

float

acosf

(

float

x

)

;

constexpr

long

double

acosl

(

long

double

x

)

;

 constexpr float*N*_t acosf*N*(float*N*_t x);

constexpr

floating-point-type

asin

(

floating-point-type

x

)

;

constexpr

float

asinf

(

float

x

)

;

constexpr

long

double

asinl

(

long

double

x

)

;

 constexpr float*N*_t asinf*N*(float*N*_t x);

constexpr

floating-point-type

atan

(

floating-point-type

x

)

;

constexpr

float

atanf

(

float

x

)

;

constexpr

long

double

atanl

(

long

double

x

)

;

 constexpr float*N*_t atanf*N*(float*N*_t x);

constexpr

floating-point-type

atan2

(

floating-point-type

y

,

floating-point-type

x

)

;

constexpr

float

atan2f

(

float

y

,

float

x

)

;

constexpr

long

double

atan2l

(

long

double

y

,

long

double

x

)

;

 constexpr float*N*_t atan2f*N*(float*N*_t y, float*N*_t x);

constexpr

floating-point-type

cos

(

floating-point-type

x

)

;

constexpr

float

cosf

(

float

x

)

;

constexpr

long

double

cosl

(

long

double

x

)

;

 constexpr float*N*_t cosf*N*(float*N*_t x);

constexpr

floating-point-type

sin

(

floating-point-type

x

)

;

constexpr

float

sinf

(

float

x

)

;

constexpr

long

double

sinl

(

long

double

x

)

;

 constexpr float*N*_t sinf*N*(float*N*_t x);

constexpr

floating-point-type

tan

(

floating-point-type

x

)

;

constexpr

float

tanf

(

float

x

)

;

constexpr

long

double

tanl

(

long

double

x

)

;

 constexpr float*N*_t tanf*N*(float*N*_t x);
constexpr *floating-point-type* acospi(*floating-point-type* x);
constexpr float acospif(float x);
constexpr long double acospil(long double x);
constexpr float*N*_t acospif*N*(float*N*_t x);
constexpr *floating-point-type* asinpi(*floating-point-type* x);
constexpr float asinpif(float x);
constexpr long double asinpil(long double x);
constexpr float*N*_t asinpif*N*(float*N*_t x);
constexpr *floating-point-type* atanpi(*floating-point-type* x);
constexpr float atanpif(float x);
constexpr long double atanpil(long double x);
constexpr float*N*_t atanf*N*(float*N*_t x);
constexpr *floating-point-type* atan2pi(*floating-point-type* y, *floating-point-type* x);
constexpr float atan2pif(float y, float x);
constexpr long double atan2pil(long double y, long double x);
constexpr float*N*_t atan2pif*N*(float*N*_t y, float*N*_t x);
constexpr *floating-point-type* cospi(*floating-point-type* x);
constexpr float cospif(float x);
constexpr long double cospil(long double x);
constexpr float*N*_t cospif*N*(float*N*_t x);
constexpr *floating-point-type* sinpi(*floating-point-type* x);
constexpr float sinpif(float x);
constexpr long double sinpil(long double x);
constexpr float*N*_t sinpif*N*(float*N*_t x);
constexpr *floating-point-type* tanpi(*floating-point-type* x);
constexpr float tanpif(float x);
constexpr long double tanpil(long double x);
constexpr float*N*_t tanpif*N*(float*N*_t x);

constexpr

floating-point-type

acosh

(

floating-point-type

x

)

;

constexpr

float

acoshf

(

float

x

)

;

constexpr

long

double

acoshl

(

long

double

x

)

;

 constexpr float*N*_t acoshf*N*(float*N*_t x);

constexpr

floating-point-type

asinh

(

floating-point-type

x

)

;

constexpr

float

asinhf

(

float

x

)

;

constexpr

long

double

asinhl

(

long

double

x

)

;

 constexpr float*N*_t asinhf*N*(float*N*_t x);

constexpr

floating-point-type

atanh

(

floating-point-type

x

)

;

constexpr

float

atanhf

(

float

x

)

;

constexpr

long

double

atanhl

(

long

double

x

)

;

 constexpr float*N*_t atanhf*N*(float*N*_t x);

constexpr

floating-point-type

cosh

(

floating-point-type

x

)

;

constexpr

float

coshf

(

float

x

)

;

constexpr

long

double

coshl

(

long

double

x

)

;

 constexpr float*N*_t coshf*N*(float*N*_t x);

constexpr

floating-point-type

sinh

(

floating-point-type

x

)

;

constexpr

float

sinhf

(

float

x

)

;

constexpr

long

double

sinhl

(

long

double

x

)

;

 constexpr float*N*_t sinhf*N*(float*N*_t x);

constexpr

floating-point-type

tanh

(

floating-point-type

x

)

;

constexpr

float

tanhf

(

float

x

)

;

constexpr

long

double

tanhl

(

long

double

x

)

;

 constexpr float*N*_t tanhf*N*(float*N*_t x);

constexpr

floating-point-type

exp

(

floating-point-type

x

)

;

constexpr

float

expf

(

float

x

)

;

constexpr

long

double

expl

(

long

double

x

)

;

 constexpr float*N*_t expf*N*(float*N*_t x);
constexpr *floating-point-type* exp10(*floating-point-type* x);
constexpr float exp10f(float x);
constexpr long double exp10l(long double x);
constexpr float*N*_t exp10f*N*(float*N*_t x);
constexpr *floating-point-type* exp10m1(*floating-point-type* x);
constexpr float exp10m1f(float x);
constexpr long double exp10m1l(long double x);
constexpr float*N*_t exp10m1f*N*(float*N*_t x);

constexpr

floating-point-type

exp2

(

floating-point-type

x

)

;

constexpr

float

exp2f

(

float

x

)

;

constexpr

long

double

exp2l

(

long

double

x

)

;

 constexpr float*N*_t exp2f*N*(float*N*_t x);
constexpr *floating-point-type* exp2m1(*floating-point-type* x);
constexpr float exp2m1f(float x);
constexpr long double exp2m1l(long double x);
constexpr float*N*_t exp2m1f*N*(float*N*_t x);

constexpr

floating-point-type

expm1

(

floating-point-type

x

)

;

constexpr

float

expm1f

(

float

x

)

;

constexpr

long

double

expm1l

(

long

double

x

)

;

 constexpr float*N*_t expm1f*N*(float*N*_t x);

constexpr

floating-point-type

frexp

(

floating-point-type

value

,

int

*

exp

)

;

constexpr

float

frexpf

(

float

value

,

int

*

exp

)

;

constexpr

long

double

frexpl

(

long

double

value

,

int

*

exp

)

;

 constexpr float*N*_t frexpf*N*(float*N*_t value, int* exp);

constexpr

int

ilogb

(

floating-point-type

x

)

;

constexpr

int

ilogbf

(

float

x

)

;

constexpr

int

ilogbl

(

long

double

x

)

;

 constexpr int ilogb(float*N*_t x);

constexpr

floating-point-type

ldexp

(

floating-point-type

x

,

int

exp

)

;

constexpr

float

ldexpf

(

float

x

,

int

exp

)

;

constexpr

long

double

ldexpl

(

long

double

x

,

int

exp

)

;

 constexpr float*N*_t ldexpf*N*(float*N*_t x, int exp);

constexpr

floating-point-type

log

(

floating-point-type

x

)

;

constexpr

float

logf

(

float

x

)

;

constexpr

long

double

logl

(

long

double

x

)

;

 constexpr float*N*_t logf*N*(float*N*_t x);

constexpr

floating-point-type

log10

(

floating-point-type

x

)

;

constexpr

float

log10f

(

float

x

)

;

constexpr

long

double

log10l

(

long

double

x

)

;

 constexpr float*N*_t log10f*N*(float*N*_t x);
constexpr *floating-point-type* log10p1(*floating-point-type* x);
constexpr float log10p1f(float x);
constexpr long double log10p1l(long double x);
constexpr float*N*_t log10p1f*N*(float*N*_t x);

constexpr

floating-point-type

log1p

(

floating-point-type

x

)

;

constexpr

float

log1pf

(

float

x

)

;

constexpr

long

double

log1pl

(

long

double

x

)

;

 constexpr float*N*_t log1pf*N*(float*N*_t x);
constexpr *floating-point-type* logp1(*floating-point-type* x);
constexpr float logp1f(float x);
constexpr long double logp1l(long double x);
constexpr float*N*_t logp1f*N*(float*N*_t x);

constexpr

floating-point-type

log2

(

floating-point-type

x

)

;

constexpr

float

log2f

(

float

x

)

;

constexpr

long

double

log2l

(

long

double

x

)

;

 constexpr float*N*_t log2f*N*(float*N*_t x);
constexpr *floating-point-type* log2p1(*floating-point-type* x);
constexpr float log2p1f(float x);
constexpr long double log2p1l(long double x);
constexpr float*N*_t log2p1f*N*(float*N*_t x);

constexpr

floating-point-type

logb

(

floating-point-type

x

)

;

constexpr

float

logbf

(

float

x

)

;

constexpr

long

double

logbl

(

long

double

x

)

;

 constexpr float*N*_t logbf*N*(float*N*_t x);

constexpr

floating-point-type

modf

(

floating-point-type

value

,

floating-point-type

*

iptr

)

;

constexpr

float

modff

(

float

value

,

float

*

iptr

)

;

constexpr

long

double

modfl

(

long

double

value

,

long

double

*

iptr

)

;

 constexpr float*N*_t modf*N*(float*N*_t value, float*N*_t* iptr);

constexpr

floating-point-type

scalbn

(

floating-point-type

x

,

int

n

)

;

constexpr

float

scalbnf

(

float

x

,

int

n

)

;

constexpr

long

double

scalbnl

(

long

double

x

,

int

n

)

;

 constexpr float*N*_t scalbnf*N*(float*N*_t x, int n);

constexpr

floating-point-type

scalbln

(

floating-point-type

x

,

long

int

n

)

;

constexpr

float

scalblnf

(

float

x

,

long

int

n

)

;

constexpr

long

double

scalblnl

(

long

double

x

,

long

int

n

)

;

 constexpr float*N*_t scalblnf*N*(float*N*_t x);

constexpr

floating-point-type

cbrt

(

floating-point-type

x

)

;

constexpr

float

cbrtf

(

float

x

)

;

constexpr

long

double

cbrtl

(

long

double

x

)

;

 constexpr float*N*_t cbrtf*N*(float*N*_t x);
constexpr *floating-point-type* compoundn(*floating-point-type* x, long long int n);
constexpr float compoundn(float x, long long int n);
constexpr long double compoundn(long double x, long long int n);
constexpr float*N*_t compoundnf*N*(float*N*_t x, long long n);

//

[c.math.abs], absolute values

constexpr

int

abs

(

int

j

)

;

//

freestanding

constexpr

long

int

abs

(

long

int

j

)

;

//

freestanding

constexpr

long

long

int

abs

(

long

long

int

j

)

;

//

freestanding

constexpr

floating-point-type

abs

(

floating-point-type

j

)

;

//

freestanding-deleted

constexpr

floating-point-type

fabs

(

floating-point-type

x

)

;

constexpr

float

fabsf

(

float

x

)

;

constexpr

long

double

fabsl

(

long

double

x

)

;

 constexpr float*N*_t fabsf*N*(float*N*_t x);

constexpr

floating-point-type

hypot

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

hypotf

(

float

x

,

float

y

)

;

constexpr

long

double

hypotl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t hypotf*N*(float*N*_t x, float*N*_t y);

//

[c.math.hypot3], three-dimensional hypotenuse

constexpr

floating-point-type

hypot

(

floating-point-type

x

,

floating-point-type

y

,

floating-point-type

z

)

;

constexpr

floating-point-type

pow

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

powf

(

float

x

,

float

y

)

;

constexpr

long

double

powl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t powf*N*(float*N*_t x, float*N*_t y);
constexpr *floating-point-type* pown(*floating-point-type* x, long long int n);
constexpr float pownf(float x, long long int n);
constexpr long double pownl(long double x, long long int n);
constexpr float*N*_t pownf*N*(float*N*_t x, long long int n);
constexpr *floating-point-type* powr(*floating-point-type* x, *floating-point-type* y);
constexpr float powrf(float x, float y);
constexpr long double powrl(long double x, long double y);
constexpr float*N*_t powrf*N*(float*N*_t x, float*N*_t y);
constexpr *floating-point-type* rootn(*floating-point-type* x, long long int n);
constexpr float rootnf(float x, long long int n);
constexpr long double rootnl(long double x, long long int n);
constexpr float*N*_t rootnf*N*(float*N*_t x, long long int n);
constexpr *floating-point-type* rsqrt(*floating-point-type* x);
constexpr float rsqrtf(float x);
constexpr long double rsqrtl(long double x);
constexpr float*N*_t rsqrtf*N*(float*N*_t x);

constexpr

floating-point-type

sqrt

(

floating-point-type

x

)

;

constexpr

float

sqrtf

(

float

x

)

;

constexpr

long

double

sqrtl

(

long

double

x

)

;

 constexpr float*N*_t sqrtf*N*(float*N*_t x);

constexpr

floating-point-type

erf

(

floating-point-type

x

)

;

constexpr

float

erff

(

float

x

)

;

constexpr

long

double

erfl

(

long

double

x

)

;

 constexpr float*N*_t erff*N*(float*N*_t x);

constexpr

floating-point-type

erfc

(

floating-point-type

x

)

;

constexpr

float

erfcf

(

float

x

)

;

constexpr

long

double

erfcl

(

long

double

x

)

;

 constexpr float*N*_t erfcf*N*(float*N*_t x);

constexpr

floating-point-type

lgamma

(

floating-point-type

x

)

;

constexpr

float

lgammaf

(

float

x

)

;

constexpr

long

double

lgammal

(

long

double

x

)

;

 constexpr float*N*_t lgammaf*N*(float*N*_t x);

constexpr

floating-point-type

tgamma

(

floating-point-type

x

)

;

constexpr

float

tgammaf

(

float

x

)

;

constexpr

long

double

tgammal

(

long

double

x

)

;

 constexpr float*N*_t tgammaf*N*(float*N*_t x);

constexpr

floating-point-type

ceil

(

floating-point-type

x

)

;

constexpr

float

ceilf

(

float

x

)

;

constexpr

long

double

ceill

(

long

double

x

)

;

 constexpr float*N*_t ceilf*N*(float*N*_t x);

constexpr

floating-point-type

floor

(

floating-point-type

x

)

;

constexpr

float

floorf

(

float

x

)

;

constexpr

long

double

floorl

(

long

double

x

)

;

 constexpr float*N*_t floorf*N*(float*N*_t x);

floating-point-type

nearbyint

(

floating-point-type

x

)

;

float

nearbyintf

(

float

x

)

;

long

double

nearbyintl

(

long

double

x

)

;

 float*N*_t nearbyintf*N*(float*N*_t x);

floating-point-type

rint

(

floating-point-type

x

)

;

float

rintf

(

float

x

)

;

long

double

rintl

(

long

double

x

)

;

 float*N*_t rintf*N*(float*N*_t x);

long

int

lrint

(

floating-point-type

x

)

;

long

int

lrintf

(

float

x

)

;

long

int

lrintl

(

long

double

x

)

;

 long int lrintf*N*(float*N*_t x);

long

long

int

llrint

(

floating-point-type

x

)

;

long

long

int

llrintf

(

float

x

)

;

long

long

int

llrintl

(

long

double

x

)

;

 long long int llrintf*N*(float*N*_t x);

constexpr

floating-point-type

round

(

floating-point-type

x

)

;

constexpr

float

roundf

(

float

x

)

;

constexpr

long

double

roundl

(

long

double

x

)

;

 constexpr float*N*_t roundf*N*(float*N*_t x);

constexpr

long

int

lround

(

floating-point-type

x

)

;

constexpr

long

int

lroundf

(

float

x

)

;

constexpr

long

int

lroundl

(

long

double

x

)

;

 constexpr long int lroundf*N*(float*N*_t x);

constexpr

long

long

int

llround

(

floating-point-type

x

)

;

constexpr

long

long

int

llroundf

(

float

x

)

;

constexpr

long

long

int

llroundl

(

long

double

x

)

;

 constexpr long long int llroundf*N*(float*N*_t x);
constexpr *floating-point-type* roundeven(*floating-point-type* x);
constexpr float roundevenf(float x);
constexpr long double roundevenl(long double x);
constexpr float*N*_t roundevenf*N*(float*N*_t x);

constexpr

floating-point-type

trunc

(

floating-point-type

x

)

;

constexpr

float

truncf

(

float

x

)

;

constexpr

long

double

truncl

(

long

double

x

)

;

 constexpr float*N*_t truncf*N*(float*N*_t x);
constexpr *floating-point-type* fromfp(*floating-point-type* x, int rnd, unsigned int width);
constexpr float fromfpf(float x, int rnd, unsigned int width);
constexpr long double fromfpl(long double x, int rnd, unsigned int width);
constexpr float*N*_t fromfpf*N*(float*N*_t x, int rnd, unsigned int width);
constexpr *floating-point-type* ufromfp(*floating-point-type* x, int rnd, unsigned int width);
constexpr float ufromfpf(float x, int rnd, unsigned int width);
constexpr long double ufromfpl(long double x, int rnd, unsigned int width);
constexpr float*N*_t ufromfpf*N*(float*N*_t x, int rnd, unsigned int width);
constexpr *floating-point-type* fromfpx(*floating-point-type* x, int rnd, unsigned int width);
constexpr float fromfpxf(float x, int rnd, unsigned int width);
constexpr long double fromfpxl(long double x, int rnd, unsigned int width);
constexpr float*N*_t fromfpxf*N*(float*N*_t x, int rnd, unsigned int width);
constexpr *floating-point-type* ufromfpx(*floating-point-type* x, int rnd, unsigned int width);
constexpr float ufromfpxf(float x, int rnd, unsigned int width);
constexpr long double ufromfpxl(long double x, int rnd, unsigned int width);
constexpr float*N*_t ufromfpxf*N*(float*N*_t x, int rnd, unsigned int width);

constexpr

floating-point-type

fmod

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

fmodf

(

float

x

,

float

y

)

;

constexpr

long

double

fmodl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t fmodf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

remainder

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

remainderf

(

float

x

,

float

y

)

;

constexpr

long

double

remainderl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t remainderf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

remquo

(

floating-point-type

x

,

floating-point-type

y

,

int

*

quo

)

;

constexpr

float

remquof

(

float

x

,

float

y

,

int

*

quo

)

;

constexpr

long

double

remquol

(

long

double

x

,

long

double

y

,

int

*

quo

)

;

 constexpr float*N*_t remquof*N*(float*N*_t x, float*N*_t, int* quo);

constexpr

floating-point-type

copysign

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

copysignf

(

float

x

,

float

y

)

;

constexpr

long

double

copysignl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t copysignf*N*(float*N*_t x, float*N*_t y);

double

nan

(

const

char

*

tagp

)

;

float

nanf

(

const

char

*

tagp

)

;

long

double

nanl

(

const

char

*

tagp

)

;

 float*N*_t nanf*N*(const char* tagp);

constexpr

floating-point-type

nextafter

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

nextafterf

(

float

x

,

float

y

)

;

constexpr

long

double

nextafterl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t nextafterf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

nexttoward

(

floating-point-type

x

,

long

double

y

)

;

constexpr

float

nexttowardf

(

float

x

,

long

double

y

)

;

constexpr

long

double

nexttowardl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t nexttowardf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

nextup

(

floating-point-type

x

)

;

constexpr

float

nextupf

(

float

x

)

;

constexpr

long

double

nextupl

(

long

double

x

)

;

 constexpr float*N*_t nextupf*N*(float*N*_t x);

constexpr

floating-point-type

nextdown

(

floating-point-type

x

)

;

constexpr

float

nextdownf

(

float

x

)

;

constexpr

long

double

nextdownl

(

long

double

x

)

;

 constexpr float*N*_t nextdownf*N*(float*N*_t x);
constexpr int canonicalize(*floating-point-type** cx, const *floating-point-type** x);
constexpr int canonicalizef(float cx, const float* x);
constexpr int canonicalizel(long double cx, const long double* x);
constexpr int canonicalizef*N*(float*N*_t* cx, const float*N*_t* x);

constexpr

floating-point-type

fdim

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

fdimf

(

float

x

,

float

y

)

;

constexpr

long

double

fdiml

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t fdimf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

fmax

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

fmaxf

(

float

x

,

float

y

)

;

constexpr

long

double

fmaxl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t fmaxf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

fmin

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

float

fminf

(

float

x

,

float

y

)

;

constexpr

long

double

fminl

(

long

double

x

,

long

double

y

)

;

 constexpr float*N*_t fminf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

fmaximum

(

floating-point-type

x

,

floating-point-type

y

)

;

 constexpr float fmaximumf(float x, float y);
constexpr long double fmaximuml(long double x, long double y);
constexpr float*N*_t fmaximumf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

fmaximum_num

(

floating-point-type

x

,

floating-point-type

y

)

;

 constexpr float fmaximum_numf(float x, float y);
constexpr long double fmaximum_numl(long double x, long double y);
constexpr float*N*_t fmaximum_numf*N*(float*N*_t x, float*N*_t y);
constexpr *floating-point-type* fmaximum_mag(*floating-point-type* x, *floating-point-type* y);
constexpr float fmaximum_magf(float x, float y);
constexpr long double fmaximum_magl(long double x, long double y);
constexpr float*N*_t fmaximum_magf*N*(float*N*_t x, float*N*_t y);
constexpr *floating-point-type* fmaximum_mag_num(*floating-point-type* x, *floating-point-type* y);
constexpr float fmaximum_mag_numf(float x, float y);
constexpr long double fmaximum_mag_numl(long double x, long double y);
constexpr float*N*_t fmaximum_mag_numf*N*(float*N*_t x, float*N*_t y);


constexpr

floating-point-type

fminimum

(

floating-point-type

x

,

floating-point-type

y

)

;

 constexpr float fminimumf(float x, float y);
constexpr long double fminimuml(long double x, long double y);
constexpr float*N*_t fminimumf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

fminimum_num

(

floating-point-type

x

,

floating-point-type

y

)

;

 constexpr float fminimum_numf(float x, float y);
constexpr long double fminimum_numl(long double x, long double y);
constexpr float*N*_t fminimum_numf*N*(float*N*_t x, float*N*_t y);
constexpr *floating-point-type* fminimum_mag(*floating-point-type* x, *floating-point-type* y);
constexpr float fminimum_magf(float x, float y);
constexpr long double fminimum_magl(long double x, long double y);
constexpr float*N*_t fminimum_magf*N*(float*N*_t x, float*N*_t y);
constexpr *floating-point-type* fminimum_mag_num(*floating-point-type* x, *floating-point-type* y);
constexpr float fmaximum_mag_numf(float x, float y);
constexpr long double fmaximum_mag_numl(long double x, long double y);
constexpr float*N*_t fmaximum_mag_numf*N*(float*N*_t x, float*N*_t y);

constexpr

floating-point-type

fma

(

floating-point-type

x

,

floating-point-type

y

,

floating-point-type

z

)

;

constexpr

float

fmaf

(

float

x

,

float

y

,

float

z

)

;

constexpr

long

double

fmal

(

long

double

x

,

long

double

y

,

long

double

z

)

;

 constexpr float*N*_t fmaf*N*(float*N*_t x, float*N*_t y, float*N*_t z);
// [c.math.narrow], narrowing operations
template<class T, class F> constexpr T fadd(F x, F y);
constexpr float fadd(*double-type* x, *double-type* y);
constexpr float faddl(long double x, long double y);
constexpr double dadd(long double x, long double y);
constexpr double daddl(long double x, long double y);
constexpr float*N*_t f*N*add(*see below* x, *see below* y);
constexpr float*N*_t f*N*addf*M*(float*M*_t x, float*M*_t y);
template<class T, class F> constexpr T fsub(F x, F y);
constexpr float fsub(*double-type* x, *double-type* y);
constexpr float fsubl(long double x, long double y);
constexpr double dsub(long double x, long double y);
constexpr double dsubl(long double x, long double y);
constexpr float*N*_t f*N*sub(*see below* x, *see below* y);
constexpr float*N*_t f*N*subf*M*(float*M*_t x, float*M*_t y);
template<class T, class F> constexpr T fmul(F x, F y);
constexpr float fmul(*double-type* x, *double-type* y);
constexpr float fmull(long double x, long double y);
constexpr double dmul(long double x, long double y);
constexpr double dmull(long double x, long double y);
constexpr float*N*_t f*N*mul(*see below* x, *see below* y);
constexpr float*N*_t f*N*mulf*M*(float*M*_t x, float*M*_t y);
template<class T, class F> constexpr T fdiv(F x, F y);
constexpr float fdiv(*double-type* x, *double-type* y);
constexpr float fdivl(long double x, long double y);
constexpr double ddiv(long double x, long double y);
constexpr double ddivl(long double x, long double y);
constexpr float*N*_t f*N*div(*see below* x, *see below* y);
constexpr float*N*_t f*N*divf*M*(float*M*_t x, float*M*_t y);
template<class T, class F> constexpr T ffma(F x, F y, F z);
constexpr float ffma(*double-type* x, *double-type* y, *double-type* z);
constexpr float ffmal(long double x, long double y, long double z);
constexpr double dfma(long double x, long double y, long double z);
constexpr double dfmal(long double x, long double y, long double z);
constexpr float*N*_t f*N*fma(*see below* x, *see below* y, *see below* z);
constexpr float*N*_t f*N*fmaf*M*(float*M*_t x, float*M*_t y, float*M*_t z);
template<class T, class F> constexpr T fsqrt(F x);
constexpr float fsqrt(*double-type* x);
constexpr float fsqrtl(long double x);
constexpr double dsqrt(long double x);
constexpr double dsqrtl(long double x);
constexpr float*N*_t f*N*sqrt(*see below* x);
constexpr float*N*_t f*N*sqrtf*M*(float*M*_t x);

//

[c.math.lerp], linear interpolation

constexpr

floating-point-type

lerp

(

floating-point-type

a

,

floating-point-type

b

,

floating-point-type

t

)

noexcept

;

//

[c.math.fpclass], classification / comparison functions

constexpr

int

fpclassify

(

floating-point-type

x

)

;

 constexpr bool iscanonical(*floating-point-type* x);

constexpr

bool

isfinite

(

floating-point-type

x

)

;

constexpr

bool

isinf

(

floating-point-type

x

)

;

constexpr

bool

isnan

(

floating-point-type

x

)

;

constexpr

bool

isnormal

(

floating-point-type

x

)

;

constexpr

bool

signbit

(

floating-point-type

x

)

;

 constexpr bool issignaling(*floating-point-type* x);

 constexpr bool issubnormal(*floating-point-type* x);

 constexpr bool iszero(*floating-point-type* x);

constexpr

bool

isgreater

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

bool

isgreaterequal

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

bool

isless

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

bool

islessequal

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

bool

islessgreater

(

floating-point-type

x

,

floating-point-type

y

)

;

constexpr

bool

isunordered

(

floating-point-type

x

,

floating-point-type

y

)

;

 constexpr bool iseqsig(*floating-point-type* x, *floating-point-type* y);
// ISO/IEC 60559 specific functions
constexpr bool totalorder(const *floating-point-type** x, // optional
const *floating-point-type** y);
constexpr bool totalorderf(const float* x, const float* y); // optional
constexpr bool totalorderl(const long double* x, const long double* y); // optional
constexpr bool totalorderf*N*(const float*N*_t* x, float*N*_t* y); // optional
constexpr bool totalordermag(const *floating-point-type** x, // optional
const *floating-point-type** y);
constexpr bool totalordermagf(const float* x, const float* y); // optional
constexpr bool totalordermagl(const long double* x, const long double* y); // optional
constexpr bool totalordermagf*N*(const float*N*_t* x, float*N*_t* y); // optional
constexpr *floating-point-type* getpayload(const *floating-point-type** x); // optional
constexpr float getpayloadf(const float* x); // optional
constexpr long double getpayloadl(const long double* x); // optional
constexpr float*N*_t getpayloadf*N*(const float*N*_t* x); // optional
constexpr int setpayload(*floating-point-type** res, *floating-point-type* pl); // optional
constexpr int setpayloadf(float* res, float pl); // optional
constexpr int setpayloadl(long double* res, long double pl); // optional
constexpr int setpayloadf*N*(float*N*_t* res, float*N*_t pl); // optional

//

[sf.cmath], mathematical special functions

//

[sf.cmath.assoc.laguerre], associated Laguerre polynomials

floating-point-type

assoc_laguerre

(

unsigned

n

,

unsigned

m

,

floating-point-type

x

)

;

float

assoc_laguerref

(

unsigned

n

,

unsigned

m

,

float

x

)

;

long

double

assoc_laguerrel

(

unsigned

n

,

unsigned

m

,

long

double

x

)

;

 float*N*_t assoc_laguerref*N*(unsigned n, unsigned m, float*N*_t x);

//

[sf.cmath.assoc.legendre], associated Legendre functions

floating-point-type

assoc_legendre

(

unsigned

l

,

unsigned

m

,

floating-point-type

x

)

;

float

assoc_legendref

(

unsigned

l

,

unsigned

m

,

float

x

)

;

long

double

assoc_legendrel

(

unsigned

l

,

unsigned

m

,

long

double

x

)

;

 float*N*_t assoc_legendref*N*(unsigned l, unsigned m, float*N*_t x);

//

[sf.cmath.beta], beta function

floating-point-type

beta

(

floating-point-type

x

,

floating-point-type

y

)

;

float

betaf

(

float

x

,

float

y

)

;

long

double

betal

(

long

double

x

,

long

double

y

)

;

 float*N*_t betaf*N*(float*N*_t x, float*N*_t y);

//

[sf.cmath.comp.ellint.1], complete elliptic integral of the first kind

floating-point-type

comp_ellint_1

(

floating-point-type

k

)

;

float

comp_ellint_1f

(

float

k

)

;

long

double

comp_ellint_1l

(

long

double

k

)

;

 float*N*_t comp_ellint_1f*N*(float*N*_t k);

//

[sf.cmath.comp.ellint.2], complete elliptic integral of the second kind

floating-point-type

comp_ellint_2

(

floating-point-type

k

)

;

float

comp_ellint_2f

(

float

k

)

;

long

double

comp_ellint_2l

(

long

double

k

)

;

 float*N*_t comp_ellint_2f*N*(float*N*_t k);

//

[sf.cmath.comp.ellint.3], complete elliptic integral of the third kind

floating-point-type

comp_ellint_3

(

floating-point-type

k

,

floating-point-type

nu

)

;

float

comp_ellint_3f

(

float

k

,

float

nu

)

;

long

double

comp_ellint_3l

(

long

double

k

,

long

double

nu

)

;

 float*N*_t comp_ellint_3f*N*(float*N*_t k, float*N*_t nu);

//

[sf.cmath.cyl.bessel.i], regular modified cylindrical Bessel functions

floating-point-type

cyl_bessel_i

(

floating-point-type

nu

,

floating-point-type

x

)

;

float

cyl_bessel_if

(

float

nu

,

float

x

)

;

long

double

cyl_bessel_il

(

long

double

nu

,

long

double

x

)

;

 float*N*_t cyl_bessel_if*N*(float*N*_t nu, float*N*_t x);

//

[sf.cmath.cyl.bessel.j], cylindrical Bessel functions of the first kind

floating-point-type

cyl_bessel_j

(

floating-point-type

nu

,

floating-point-type

x

)

;

float

cyl_bessel_jf

(

float

nu

,

float

x

)

;

long

double

cyl_bessel_jl

(

long

double

nu

,

long

double

x

)

;

 float*N*_t cyl_bessel_jf*N*(float*N*_t nu, float*N*_t x);

//

[sf.cmath.cyl.bessel.k], irregular modified cylindrical Bessel functions

floating-point-type

cyl_bessel_k

(

floating-point-type

nu

,

floating-point-type

x

)

;

float

cyl_bessel_kf

(

float

nu

,

float

x

)

;

long

double

cyl_bessel_kl

(

long

double

nu

,

long

double

x

)

;

 float*N*_t cyl_bessel_kf*N*(float*N*_t nu, float*N*_t x);

//

[sf.cmath.cyl.neumann], cylindrical Neumann functions

//

cylindrical Bessel functions of the second kind

floating-point-type

cyl_neumann

(

floating-point-type

nu

,

floating-point-type

x

)

;

float

cyl_neumannf

(

float

nu

,

float

x

)

;

long

double

cyl_neumannl

(

long

double

nu

,

long

double

x

)

;

 float*N*_t cyl_neumannf*N*(float*N*_t nu, float*N*_t x);

//

[sf.cmath.ellint.1], incomplete elliptic integral of the first kind

floating-point-type

ellint_1

(

floating-point-type

k

,

floating-point-type

phi

)

;

float

ellint_1f

(

float

k

,

float

phi

)

;

long

double

ellint_1l

(

long

double

k

,

long

double

phi

)

;

 float*N*_t ellint_1f*N*(float*N*_t k, float*N*_t phi);

//

[sf.cmath.ellint.2], incomplete elliptic integral of the second kind

floating-point-type

ellint_2

(

floating-point-type

k

,

floating-point-type

phi

)

;

float

ellint_2f

(

float

k

,

float

phi

)

;

long

double

ellint_2l

(

long

double

k

,

long

double

phi

)

;

 float*N*_t ellint_2f*N*(float*N*_t k, float*N*_t phi);

//

[sf.cmath.ellint.3], incomplete elliptic integral of the third kind

floating-point-type

ellint_3

(

floating-point-type

k

,

floating-point-type

nu

,

floating-point-type

phi

)

;

float

ellint_3f

(

float

k

,

float

nu

,

float

phi

)

;

long

double

ellint_3l

(

long

double

k

,

long

double

nu

,

long

double

phi

)

;

 float*N*_t ellint_3f*N*(float*N*_t k, float*N*_t nu, float*N*_t phi);

//

[sf.cmath.expint], exponential integral

floating-point-type

expint

(

floating-point-type

x

)

;

float

expintf

(

float

x

)

;

long

double

expintl

(

long

double

x

)

;

 float*N*_t expintf*N*(float*N*_t x);

//

[sf.cmath.hermite], Hermite polynomials

floating-point-type

hermite

(

unsigned

n

,

floating-point-type

x

)

;

float

hermitef

(

unsigned

n

,

float

x

)

;

long

double

hermitel

(

unsigned

n

,

long

double

x

)

;

 float*N*_t hermitef*N*(unsigned n, float*N*_t x);

//

[sf.cmath.laguerre], Laguerre polynomials

floating-point-type

laguerre

(

unsigned

n

,

floating-point-type

x

)

;

float

laguerref

(

unsigned

n

,

float

x

)

;

long

double

laguerrel

(

unsigned

n

,

long

double

x

)

;

 float*N*_t laguerref*N*(unsigned n, float*N*_t x);

//

[sf.cmath.legendre], Legendre polynomials

floating-point-type

legendre

(

unsigned

l

,

floating-point-type

x

)

;

float

legendref

(

unsigned

l

,

float

x

)

;

long

double

legendrel

(

unsigned

l

,

long

double

x

)

;

 float*N*_t legendref*N*(unsigned l, float*N*_t x);

//

[sf.cmath.riemann.zeta], Riemann zeta function

floating-point-type

riemann_zeta

(

floating-point-type

x

)

;

float

riemann_zetaf

(

float

x

)

;

long

double

riemann_zetal

(

long

double

x

)

;

 float*N*_t riemann_zetaf*N*(float*N*_t x);

//

[sf.cmath.sph.bessel], spherical Bessel functions of the first kind

floating-point-type

sph_bessel

(

unsigned

n

,

floating-point-type

x

)

;

float

sph_besself

(

unsigned

n

,

float

x

)

;

long

double

sph_bessell

(

unsigned

n

,

long

double

x

)

;

 float*N*_t sph_besself*N*(unsigned n, float*N*_t x);

//

[sf.cmath.sph.legendre], spherical associated Legendre functions

floating-point-type

sph_legendre

(

unsigned

l

,

unsigned

m

,

floating-point-type

theta

)

;

float

sph_legendref

(

unsigned

l

,

unsigned

m

,

float

theta

)

;

long

double

sph_legendrel

(

unsigned

l

,

unsigned

m

,

long

double

theta

)

;

 float*N*_t sph_legendref*N*(unsigned l, unsigned m, float*N*_t theta);

//

[sf.cmath.sph.neumann], spherical Neumann functions;

//

spherical Bessel functions of the second kind

floating-point-type

sph_neumann

(

unsigned

n

,

floating-point-type

x

)

;

float

sph_neumannf

(

unsigned

n

,

float

x

)

;

long

double

sph_neumannl

(

unsigned

n

,

long

double

x

)

;

 float*N*_t sph_neumannf*N*(unsigned n, float*N*_t x);

}

Change [[cmath.syn] paragraph 1](https://eel.is/c++draft/cmath.syn#1) as follows:

The contents and meaning of the header `<cmath>` are a subset of the C standard library header `<math.h>` and only the declarations shown in the synopsis above are present, with the addition of a three-dimensional hypotenuse function, a linear interpolation function, and the mathematical special functions described in [[sf.cmath]](https://eel.is/c++draft/sf.cmath).

Change [[cmath.syn] paragraph 2](https://eel.is/c++draft/cmath.syn#2) as follows:

<del>For each function with at least one parameter of type `*floating-point-type*`, the implementation provides an overload for each cv-unqualified floating-point type ([[basic.fundamental]](https://eel.is/c++draft/basic.fundamental))</del> <ins>Multiple functions above are specified using a type placeholder, for which the implementation providese an overload for each type in a set,</ins> where all uses of <del>`*floating-point-type*`</del> <ins>the type placeholder</ins> in the function signature are replaced with that floating-point type.

- <ins> For the type placeholder `*floating-point-type*`, the set of types is all cv-unqualified floating-point types. </ins>
- <ins> For the type placeholder `*double-type*`, the set of types is `double` and `long double`. </ins>
- <ins> For the type placeholder `float*N*_t`, the set of types is `float16_t`, `float32_t`, `float64_t`, and `float128_t`, if defined. The `*N*` placeholder in the function name is replaced with the corresponding width in the type name. </ins>

Insert a new item immediately following [[cmath.syn] paragraph 2](https://eel.is/c++draft/cmath.syn#2):

¶ Let `*common-floating-point-type*` and `*common-double-type*` be the following exposition-only alias templates:

template

<

class

...

Ts

>

using

common-floating-point-type

=

see below

;

template

<

class

...

Ts

>

using

common-double-type

=

see below

;

¶ *Constraints*: Each type in the pack `Ts` is a cv-unqualified arithmetic type ([[basic.fundamental]](https://eel.is/c++draft/basic.fundamental)).

¶ Let `R` be defined as follows:

- For `*common-floating-point-type*`, let `R` be the floating-point type with the greatest floating-point conversion rank and greatest floating-point conversion subrank among the types in `Ts`, where integer types are considered to have the same floating-point conversion rank as `double`.
- For `*common-double-type*`, let `R` be `long double` if any of the types in `Ts` is `long double`, and `double` otherwise.

¶ *Mandates*: `R` is defined.

¶ *Result*: `R`.

`*common-floating-point-type*` is just following the existing semantics of [[cmath.syn] paragraph 3](https://eel.is/c++draft/cmath.syn#3) in the form of an exposition-only alias template.

`*common-double-type*` is meant to emulate the behavior of the `<tgmath.h>` macros `fadd`, `fsub`, etc.

For `dadd`, `dsub`, etc. no such thing is necessary because without decimal floating-point types, the behavior is always to convert all arguments to `long double`.

Change [[cmath.syn] paragraph 3](https://eel.is/c++draft/cmath.syn#3) as follows:

For each function with at least one parameter <del>of type `*floating-point-type*`</del> <ins>declared with a type placeholder,</ins> other than `abs`, the implementation also provides additional overloads sufficient to ensure that, if every argument corresponding to a <del>`*floating-point-type*`</del> <ins>type placeholder</ins> parameter has arithmetic type, then every such argument is effectively cast to <del>the floating-point type with the greatest floating-point conversion rank and greatest floating-point conversion subrank among the types of all such arguments, where arguments of integer type are considered to have the same floating-point conversion rank as `double`</del>

- <ins>`*common-double-type*<Args...>` if the type placeholder is `*double-type*`, and</ins>
- <ins>`*common-floating-point-type*<Args...>` otherwise.</ins>

If <del>no such floating-point type with the greatest rank and subrank exists</del> <ins>that specialization of the alias template is ill-formed</ins>, then overload resolution does not result in a usable candidate ([[over.match.general]](https://eel.is/c++draft/over.match.general)) from the overloads provided by the implementation.

Add a new paragraphs immediately following [[cmath.syn] paragraph 3](https://eel.is/c++draft/cmath.syn#3):

The implementation may provide additional overloads of `*p*add`, `*p*sub`, `*p*mul`, `*p*div`, `*p*fma`, and `*p*sqrt`, for any prefix `*p*`, with parameters of cv-unqualified arithmetic types to ensure consistent behavior with the corresponding macro in C header `<tgmath.h>`.

While the implementation is generally free to provide additional overloads, this is not allowed to alter the behavior of a conforming program. If an implementation provided an extended floating-point type `_Decimal128`, `dadd` would need to convert arguments of type `_Decimal128` to `long double`, but the C23 behavior is to call `daddd128`.

This would not be the case if `_Decimal128` was a compiler extension, in which case the program isn't standard C++ anyway, and the implementation can do whatever it wants.

The functions whose names begin with `totalorder`, `totalordermag`, `getpayload`, or `setpayload` are only provided if `numeric_limits<T>::is_iec559` is `true` for the floating-point type `T` in the function signature (possibly following the placeholder substitution described above).

### [c.math.narrow]

Add a new subclause as follows:

### Narrowing operations [c.math.narrow]

constexpr

float

f

op

(

long

double

x

/*

...

*/

)

;

constexpr

double

d

op

(

long

double

x

/*

...

*/

)

;

constexpr

float

N

_t

f

N

op

(

see below

x

/*

...

*/

)

;

constexpr

float

N

_t

f

N

op

f

M

(

float

M

_t

x

/*

...

*/

)

;

¶ Let `*op*` be a placeholder for `add`, `sub`, `mul`, `div`, `fma`, or `sqrt`.

¶ For each of the functions `f*N**op*` and `f*N**op*f*M*`, the implementation provides an overload for every pair `*N*` and `*M*` if `*N*` < `*M*` and the aliases `float*N*_t` and `float*M*_t` are defined, where every placeholder `*N*` and `*M*` in the function signature is replaced with the corresponding integers.

¶ For each function `*f*M**op*f*N**`, the implementation also defines a macro `FP_FAST_F*M**up*F*N*`, where `*up*` is `*op*` in uppercase.

¶ *Effects*: Each of the macros and overloads `f*op*` and `d*op*` has the same behavior as the function `f*op*l` and `d*op*l`, respectively. Each of the overloads `f*N**op*` has the same behavior as the corresponding function `f*N**op*f*M*` with the same parameter types.

¶ [*Example*: If only `float32_t`, `float64_t`, and `float128_t` are defined, the implementation provides the overloads

#define FP_FAST_F32SQRTF64

see above

#define FP_FAST_F32SQRTF128

see above

#define FP_FAST_F64SQRTF128

see above

constexpr

float32_t

f32sqrt

(

float64_t

x

)

;

constexpr

float32_t

f32sqrt

(

float128_t

x

)

;

constexpr

float64_t

f64sqrt

(

float128_t

x

)

;

constexpr

float32_t

f32sqrtf64

(

float64_t

x

)

;

constexpr

float32_t

f32sqrtf128

(

float128_t

x

)

;

constexpr

float64_t

f64sqrtf128

(

float128_t

x

)

;

where `*op*` is `sqrt`. — *end example*]

template

<

class

T

,

class

F1

,

class

F2

>

constexpr

T

fadd

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

,

class

F2

>

constexpr

T

fsub

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

,

class

F2

>

constexpr

T

fmul

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

>

constexpr

T

fdiv

(

F1

x

,

F2

y

)

;

template

<

class

T

,

class

F1

,

class

F2

,

class

F3

>

constexpr

T

ffma

(

F1

x

,

F2

y

,

F3

z

)

;

template

<

class

T

,

class

F1

>

constexpr

T

fsqrt

(

F1

x

)

;

¶ Let `Fs` be a pack of template type parameters following `T`. Let `F` be the type determined as follows:

- If `T` is `double` or if any type in `Fs` is `long double`, `F` is `long double`.
- Otherwise, if `T` is `float`, `F` is `double`.
- Otherwise, if `T` is an extended floating-point type named by an alias `std::float*N*_t` ([[stdfloat.syn]](https://eel.is/c++draft/stdfloat.syn)), `F` is the type named by `std::float*M*_t`, where M=N×2, if such an alias is defined.
- Otherwise, `F` is implementation-defined and may not exist.

¶ *Constraints*:

- Each type in `Fs` is a cv-unqualified arithmetic type.
- `F` exists.
- `((numeric_limimts<Fs>::radix == numeric_limits<F>::radix) && ...)` is `true`.
- `T` is a cv-unqualified floating-point type other than `long double`.

[*Example*: It is implementation-defined whether the constraints of `fadd<bfloat16_t, float32_t>` are satisfied. — *end example*]

¶ *Effects*: All parameters are converted to prvalues of type `F`. Each of the function templates has the same behavior as the corresponding non-template overload with the same name, if that overload had return type `T` and parameters all of type `F`.

¶ *Remarks*: The `FP_FAST` macros also relate to specializations of these function templates. [*Example*: `FP_FAST_DSQRTL` relates to `dsqrtl` and `fsqrt<double, long double>`. — *end example*]

### [sf.cmath]

For every overload set in this subclause, add the same overload as shown in the synopsis changes above:

Change the declaration in [[sf.cmath.assoc.laguerre]](https://eel.is/c++draft/sf.cmath.assoc.laguerre) as follows:

floating-point-type

assoc_laguerre

(

unsigned

n

,

unsigned

m

,

floating-point-type

x

)

;

float

assoc_laguerref

(

unsigned

n

,

unsigned

m

,

float

x

)

;

long

double

assoc_laguerrel

(

unsigned

n

,

unsigned

m

,

long

double

x

)

;

float*N*_t assoc_laguerref*N*(unsigned n, unsigned m, float*N*_t x);

## Acknowledgements

Thanks to Hubert Tong for reviewing the library wording and pointing out asymmetries with the behavior of `<tgmath.h>` macros.

## References

[N5014]

Thomas Köppe.

Working Draft, Programming Languages — C++

2025-08-05

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5014.pdf

[P3348R4]

Jonathan Wakely.

C++26 should refer to C23 not C17

2025-06-19

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3348r4.pdf

[P3008R6]

Gonzalo Brito Gadeschi, David Sankel.

Atomic floating-point min/max

2025-06-19

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3008r6.html
