Values of floating-point types
- Document number:
- P3938R2
- Date:
2026-10-11 - Audience:
- SG6, EWG, CWG
- Project:
- ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
- Reply-to:
- Jan Schultke <janschultke@gmail.com>
- GitHub Issue:
- wg21.link/P3938/github
- Source:
- github.com/eisenwave/cpp-proposals/blob/master/src/floating-point-values.cow
Contents
Revision history
Changes since R1
Changes since R0
Introduction
Representation levels and defining value
Template argument equivalence problem
Issues with Level 4 values
Modeling excess precision
Solution: associated representations
Solving the problem of quiet_Nan() and signaling_NaN()
Q&A
Do infinity and NaN exist from a core language perspective?
Can there be an unsigned zero, infinity, or NaN value, or are all floating-point values signed?
Conversely, can there be a signed zero, infinity, or NaN value?
Can there be a negative zero and an unsigned infinity, or is the "signedness requirement" all-or-none?
Is negative zero negative? What about infinity and NaN?
Is negative NaN
distinct from positive NaN
?
Are different NaN payloads distinct values?
Can an extended floating-point type have no finite values?
Does the core language need to distinguish between normal/subnormal numbers?
Are there values beyond finite values, infinity, and NaN?
What does it mean for a type to adhere to ISO/IEC 60559
?
Is 0 . 0 positive or negative zero?
Are arithmetic operations required to preserve the sign of zero?
How does template argument equivalence work for floating-point types?
Impact on the standard
Impact on implementations
Wording
[lex]
[basic]
[expr]
[temp]
[support]
[meta]
References
1. Revision history
1.1. Changes since R1
- Simplified §2. Introduction to no longer duplicate §3. Q&A questions
-
Added §2.1. Representation levels and defining
value
, introducing a model ofvalue
consistent with Level 2 of ISO/IEC 60559, as well as anassociated representation
property consistent with Level 4 - Ensured in § [basic] that zero is always representable in a floating-point type
- Discussed in §3.8. Can an extended floating-point type have no finite values? that zero should always be representable in a floating-point type
1.2. Changes since R0
- Rationalized the status quo in §3.5. Is negative zero negative? What about infinity and NaN?
- Rebased §6. Wording on N5032
- In §6. Wording, fixed improper handling of negative zero
floating-point-literal s - In §6. Wording, referenced [CWG3129]
-
In §6. Wording, improved handling of signaling NaNs by relaxing the definition of
adheres to ISO/IEC 60559
2. Introduction
The core language wording in the C++ standard does not specify what values a floating-point type may represent. There are a few questions that have no obvious answer, such as whether negative zero is distinct from positive zero, and many other questions listed in the Q&A.
Bits of information may be found in various parts of the standard,
such as in the concept of "adhering to ISO/IEC 60559",
requirements,
the inheritance of C features such as , etc.
However, some of these questions are so deeply unclear that a core issue
alone wouldn't be sufficient to solve the problem.
The goal of this paper is to answer these questions, not by making any evolutionary changes to the language, but by investigating what the status quo is and turning that into wording.
2.1. Representation levels and defining value
When discussing R1 of this paper in Brno, SG6 discussed the issue of what constitutes distinct floating-point values, and agreed that there is only one NaN value:
POLL: SG6 agrees that by “value” of a floating point type we generally mean the sense of value referred to as “Level 2” in Table 3.1 of ISO/IEC 60559 (2020): {-∞…-0} ∪ {+0…+∞} ∪ {NaN}; “Floating point data — an algebraically closed system” (As opposed to “Extended real numbers” or “Representations of floating point data”)
SF F N A SA 5 10 0 0 0 Outcome: strong consensus!
This poll refers to the following table in ISO/IEC 60559:
Table 3.1 — Relationships between different specification levels for a particular format
Level 1 {−∞ … 0 … +∞} Extended real numbers. many-to-one ↓ rounding ↑ projection (except for NaN) Level 2 {−∞ … −0} ∪ {+0 … +∞} ∪ {NaN} Floating point data — an algebraically closed system. one-to-many ↓ representation specification ↑ many-to-one Level 3 (sign, exponent, significand) ∪ {−∞, +∞} ∪ qNaN ∪ sNaN Representations of floating-point data. one-to-many ↓ encoding for representations of floating-point data ↑ many-to-one Level 4 0111000... Bit strings.
2.1.1. Template argument equivalence problem
However, this Level 2
model runs into a problem with the existing C++ mechanics:
§3.14. How does template argument equivalence work for floating-point types?
explains that every possible bit pattern of a floating-point type is treated as a distinct value,
suggesting that our definition of value
is Level 4.
After all, a template argument is simply a value subject to lvalue-to-rvalue conversion,
so this can only work if prvalues carry every minute detail of the object representation.
2.1.2. Issues with Level 4 values
However, defining value
to be at Level 4 is not a good idea
because it lacks any kind of abstraction.
Simply saying that
would be a wording defect
because the wording is ambiguous.
We didn't specify the the sign bit of the result,
and we didn't specify the quantum exponent of the result in the case of decimal floating-point types.
We would need to say something like
returns the value zero
returns an implementation-defined value representing the number zero.std :: acos ( 1 )
Another problem is that the wording in [conv.fpprom] would be defective because it states
A prvalue of type
can be converted to a prvalue of typefloat . The value is unchanged.double
If every bit pattern is a distinct value, then changing the amount of bits in the operand is obviously changing the value, so this requirement becomes unimplementable.
In general, a Level 4 model of value
either makes our wording defective
or forces us to litter every part of the specification with
implementation-defined
or unspecified
,
and also results in a significant deviation from the C23 wording,
which we generally try to stay symmetrical with.
2.1.3. Modeling excess precision
Another problem to solve is that C++ allows floating-point values to be represented with excess precision.
may be a valid prvalue
of type
despite far exceeding the range of .
This results in funny behavior such as in:
The value of is either or NaN
depending on whether the
Excess precision is not just a hypothetical issue;
GCC uses excess precision for to use the hardware's binary32 support,
rather than strictly rounding every operation to binary16.
Excess precision with a Level 4 value is simply nonsensical.
Clearly, value
is somewhat abstract and detached from bit patterns,
and there are some values that do not correspond to any bit pattern.
2.1.4. Solution: associated representations
The standard is currently contradictory on what constitutes a value
,
which is ultimately caused by using the same term to talk about different levels of abstraction.
Simply saying that our value
is Level 2 breaks some things,
and saying it is Level 4 breaks other things.
To solve this, I propose a new term associated representation
that is a property of values and that provides the additional Level 4 information
so that value
can be Level 2:
- The associated representation of a floating-point value inside an object is the value representation of that object.
- When lvalue-to-rvalue conversion loads the prvalue out of an object, the associated representation is preserved.
- In various other cases, the associated representation is unspecified, such as when computing the sum of two floating-point numbers.
This new term adds immense flexibility:
-
By strictly specifying associated representations
or requiring them to be implementation-defined
(and thus deterministic),
we can express deterministic floating-point implementations in our wording.
This is useful if we ever want to add a
deterministic mode
, such as implemented by WASM's deterministic profile. - By leaving associated representations unspecified, we can express optimization opportunities and additional implementation freedom.
-
Excess precision is allowed in those situations
where the associated representation is unspecified.
Since
value
is Level 2, it is still an abstract term and capable of referring to values that do not have a corresponding bit pattern. -
We can word the behavior of CPU architectures where adjustments like canonicalization
or flushing of subnormals to zero take place immediately upon lvalue-to-rvalue conversion,
i.e. when loading a value into a register:
-
Subnormal flushing would be expressed as the implementation not supporting
subnormals due to precision constraints.
When an object stores a subnormal anyway
(perhaps as the result of
), the flushing would result in no change in value (because the value is zero), but would change the associated representation.std :: start_lifetime_as - Similarly, canonicalization of NaNs does not change the value (because there is only one NaN value), but does change the NaN payload.
-
Subnormal flushing would be expressed as the implementation not supporting
subnormals due to precision constraints.
When an object stores a subnormal anyway
(perhaps as the result of
- We can define template argument equivalence in terms of associated representations and ensure that the lvalue-to-rvalue conversion taking place during template argument passing preserves the associated representation.
2.1.5. Solving the problem of quiet_Nan() and signaling_NaN()
One pre-existing problem is that and
return NaN values by value.
Ever passing signaling NaNs by value is a problem because it disallows
the implementation of raising floating-point exceptions when loading a signaling NaN from memory
or when passing it around in registers.
by pointer in and other functions.
Macros such as can also read the representation of the argument directly
if given an lvalue.
This is why there is no concrete function.
The wording of these two functions only makes sense at Level 3, not at either previously mentioned specification level:
-
If
value
is Level 2, this actually means that both functions have the same result (a NaN), and it could even mean thatreturns a signaling NaN andquiet_NaN ( ) returns a quiet NaN.signaling_NaN ( ) -
If
value
is Level 4, this wording is defective becausequiet NaN
does not fully specify the bit pattern of the result. We should have said something about the payload being implementation-defined or unspecified, and should have said something about the sign bit.
The associated representation
model lets us square that circle:
we can say that both and
return the same value
but with different associated representations.
3. Q&A
In the following subsections, the paper tries to find a good answer to the questions above. These answers are primarily based on the existing wording and on existing implementation practice.
3.1. Do infinity and NaN exist from a core language perspective?
Yes.
[basic.fundamental] mentions infinity.
While NaN is not mentioned explicitly,
implies it.
At the very least, floating-point types may represent
- zero, for zero-initialization to make sense,
negative zero
, since both C and C++ already mention this term many times, and- infinity, qNaN, and sNan, [numeric.limits] to make sense and to have types that adhere to ISO/IEC 60559.
3.2. Can there be an unsigned zero, infinity, or NaN value, or are all floating-point values signed?
There can be fully unsigned floating-point numbers.
The C standard explicitly mentions unsigned infinity and unsigned zero,
and different NaN signs are typically not distinct values.
The C++ standard presumably inherits the C model because all of the
functions are stated to work like C23's .
There is no C++ restriction on .
Furthermore, [numeric.limits.members]
states that is meaningful for all specializations,
so there is presumably no requirement that a floating-point type
or any of its values are signed.
3.3. Conversely, can there be a signed zero, infinity, or NaN value?
Presumably. The C++ standard mentions negative zero and negative infinity in a number of places. NaN with negative sign bit and NaN with positive sign bit are usually not considered distinct values (e.g. ISO/IEC 60559), but the C++ standard has no wording that would prohibit that distinction.
3.4. Can there be a negative zero and an unsigned infinity, or is the "signedness requirement" all-or-none?
It's not all-or-none. There are floating-point types that adhere to ISO/IEC 60559, and these do not have a distinct negative and positive NaN, so it cannot be all-or-none.
3.5. Is negative zero negative? What about infinity and NaN?
No.
The wording uses negative
in the less than zero
sense ([complex.numbers] negative value
to values which are less than zero,
so negative zero and negative NaN
(NaN with negative sign bit) are not negative.
Negative infinity is negative because it compares less than zero.
should produce negative infinity,
if well-defined, which it currently isn't.
However, this would be a major deviation from the C wording,
and we usually try to keep the C++ floating-point wording symmetrical.
Also, the ISO/IEC 60559 phrase has negative sign bit
includes negative zero as well.
In most contexts, negative zero is treated the same as positive zero,
and it would impose a wording burden if one was negative but not the other.
3.6. Is negative NaN
distinct from positive NaN
?
Presumably. While ISO/IEC 60559 does not consider NaNs with different sign bit to be distinct values, the C++ standard does not prohibit such a model.
3.7. Are different NaN payloads distinct values?
Sometimes.
and
are two NaNs distinguished only by payload.
However, not every implementation treats these distinctly.
For example, when compiling to WASM,
none of the or instructions handle signaling NaNs.
3.8. Can an extended floating-point type have no finite values?
No.
This would make members such as
worded in a nonsensical way.
Furthermore, C23 §6.7.11 paragraph 14
involves initialization to zero
of arithmetic types,
so C23 necessitates zero.
By proxy, must return zero because zero exists,
and C++'s must return zero as well.
This doesn't necessarily apply to an extended floating-point type
that is not C-compatible,
but any type that exists in practice is subject to these requirements.
It is reasonable to clarify that zero exists explicitly in the wording.
3.9. Does the core language need to distinguish between normal/subnormal numbers?
No.
Subnormals either get flushed
to zero,
meaning that they are alternative representations of zero, numerically,
or they are simply finite numbers like any other.
The classification of normal
and subnormal
is an implementation detail of the floating-point format.
3.10. Are there values beyond finite values, infinity, and NaN?
The exotic and surprising part is that floating-point types may represent additional implementation-defined values beyond finite values, infinity, and NaN. This is backed by
- C23 §5.2.5.3.3 [Characteristics of floating types <float.h>] paragraph 8, and
- C23 §7.12 [Mathematics <math.h>] paragraph 12.
These paragraphs support the existence of such additional implementation-defined
classifications.
C++ inherits the behavior of from ,
so it must support the same classifications to be compatible.
macro for
VAX floating-point numbers
may yield (reserved operand),
which raises a reserved operand fault,
i.e. a CPU exception when processed,
similar to integer division by zero.
This is different from signaling NaN in that by default, signaling NaN only raises a floating-point exception but doesn't trap.
While neither the C23 wording nor the C++ wording handles these extra implementation-defined classifications well, they nonetheless exist, and it seems like an unmotivated breaking change to drop support for them.
3.11. What does it mean for a type to adhere to ISO/IEC 60559
?
It just means that the value representation is one of binary16, binary32, binary64, binary128, or some extended or decimal floating-point format specified in ISO/IEC 60559.
When it comes to operations,
the C++ standard specifies no mapping between expressions (e.g. )
and the ISO/IEC 60559 operations (e.g. division
).
In fact, it seems to deliberately deviate from the ISO/IEC 60559 operations
by declaring division by zero to be undefined behavior,
even for floating-point types ([expr.mul]).
is not infinity,
but UB by omission
or UB by wording hole
,
even if adheres to ISO/IEC 60559
.
While it would be desirable to align the C++ operations with ISO/IEC 60559 operations, this would require significant wording effort. There exists no core wording that even attempts at doing so. Note that implementations don't always compute results correctly rounded (with the greatest available precision), while the ISO/IEC 60559 operations are usually correctly rounded. Therefore, aligning the C++ expressions with ISO/IEC 60559 may require changes to most implementations.
3.12. Is 0 . 0 positive or negative zero?
Presumably positive.
The C++ standard does not mandate a specific sign for
3.13. Are arithmetic operations required to preserve the sign of zero?
Presumably no. While the ISO/IEC 60559 multiplication operation preserves the sign bit when multiplying with 1, the C++ standard does not clearly mandate such behavior.
Especially considering that not every type adheres to ISO/IEC 60559,
we should require a specific handling of sign bits, explicitly.
For example, the unary operator should be required to flip the sign bit
even for zero,
otherwise may not be a spelling of negative zero,
as users rely on.
3.14. How does template argument equivalence work for floating-point types?
In practice, it is based on bitwise identical values. [temp.type] states that
Two values are template-argument-equivalent if they are of the same type and
- they are of integral type and their values are the same, or
- they are of floating-point type and their values are identical, or
- […]
The distinction between same
and identical
is not obvious.
It was added during C++20 NB comment resolution by [P1907R1],
after [P1714R1]
(the paper which originally added support for floating-point template parameters)
was rejected.
The original paper used the terminology identical value representations
,
which makes the intent obvious,
unlike the current wording.
GCC, Clang, and MSVC implement the design of the original paper by mangling the bit-casting to an integer and mangling it into the name.
with two different qNaNs payloads results in two distinct
instantiations, despite there only being only one distinct qNaN value,
at least from an ISO/IEC 60559 perspective.
Both GCC and Clang emit the assembly:
_Z1fILf7fc00000EEvv:
ret
_Z1fILf7fc00001EEvv:
ret
The wording should be clarified to match the design of the original paper
and to match what implementations actually do.
Creating a distinct instantiation for every bit pattern is the most useful behavior anyway;
it would be impossible to deliberately wrap a NaN payload of choice
in otherwise, for example.
4. Impact on the standard
The clarify the floating-point specification, a bit of additional wording is required.
This paper only picks the low-hanging fruits
,
so to speak.
In the long run, specifying the handling of NaNs and infinities by C++ expressions,
documenting ISO/IEC 60559 conformance,
and other large changes may be desirable.
However, those would require much greater changes.
5. Impact on implementations
All proposed wording changes document the current behavior of major implementations.
6. Wording
The changes are relative to [N5032].
[lex]
Change [lex.fcon] paragraph 3 as follows:
If the scaled value is not in the range of representable values for its type,
the program is ill-formed.
Otherwise, the value of a
If [CWG3129] has not yet been approved at the time of writing, add a new example attached to [lex.fcon] paragraph 3:
[Example:
is positive zero, and
is negative zero if
has a signed zero ([basic.fundamental], [expr.unary.op]).
— end example]
Otherwise, if the proposed resolution of [CWG3129] has been merged, change the existing example as follows:
[Example:
The following example assumes that is supported ([basic.extended.fp]).
— end example]
[basic]
Immediately preceding [basic.fundamental] paragraph 13, insert several new paragraphs:
A floating-point type adheres to ISO/IEC 60559 if its value representation is one of the floating-point formats specified in ISO/IEC 60559 and can represent the sets of floating-point values listed in ISO/IEC 60559, except that it is implementation-defined whether all signaling NaN values are treated as a quiet NaN instead.
[Note:
Adherence to ISO/IEC 60559 does not imply that operations on floating-point types
behave exactly as specified in that standard.
For example, the behavior of addition in C++ ([expr.add])
can differ from the addition
operation in ISO/IEC 60559.
— end note]
A floating-point type represents at least a subset of rational numbers including zero. Depending on the implementation-defined value representation for the type, it may additionally represent the non-finite values
- negative infinity,
- positive infinity,
Not a Number
(NaN), and- further implementation-defined values.
A floating-point type which adheres to ISO/IEC 60559 is capable of representing a distinct negative value for every representable finite positive value, including for zero.
[Note: A floating-point type which adheres to ISO/IEC 60559 is capable of representing a negative and positive variant of finite values and infinity. Some representations of NaN are quiet and some are signaling, but there is only a single NaN value. — end note]
A value of floating-point type additionally has an associated representation, which is a (possibly partial) constraint on the value representation of an object which is modified to have that value. The associated representation of an object is the value representation of that object. Unless otherwise stated, the associated representation of a value is unspecified.
[Example: ISO/IEC 60559 floating-point types can only represent a single NaN value, but its associated representation may constrain it to be a quiet NaN or signaling NaN when assigned to an object. — end example]
Floating constants of decimal floating type that have the same numerical value but different quantum exponents have distinguishable internal representations.
Immediately preceding [basic.fundamental] paragraph 14, insert a new paragraph:
A value is negative if and only if it compares less than 0 ([expr.rel]).
[Note: Negative zeros and NaNs are not negative values. — end note]
[expr]
At the end of [expr.pre], insert a new paragraph:
Unless otherwise stated, it is unspecified which of the alternative representations for a value is chosen as the result of an expression. Furthermore, if the result is of a floating-point type that can represent negative and positive zero, it is implementation-defined which zero is chosen as the result of the expression.
Change [conv.lval] paragraph 3 as follows:
The result of the conversion is determined according to the following rules:
- […]
-
Otherwise, the object indicated by the glvalue is read ([defns.access]).
Let
be the value contained in the object. The prvalue result isV -
the value of type T congruent ([basic.fundamental]) to
ifV is an integer type,T -
the result of
ifreinterpret_cast < T > ( reinterpret_cast < std :: uintptr_t > ( V ) ) is volatile-qualified andT is a pointer value that is not valid in the context of the evaluation ([basic.compound]),V and -
ifV is a floating-point type, where the associated representation of the result is that of the object, andT otherwise.V
-
the value of type T congruent ([basic.fundamental]) to
While there are value-altering mechanisms like subnormal flushing and canonicalization, these do not take place when simply moving between memory and floating-point registers. Subnormal flushing instead takes place on input to arithmetic instructions or when an output is generated by an arithmetic instruction. From the perspective of the abstract machine, this would simply mean that e.g. floating-point addition is an imprecise operation.
Change [conv.fpint] paragraph 2 as follows:
A prvalue of an integer type or of an unscoped enumeration type can be converted to a prvalue of a floating-point type. The result is exact if possible. If the value being converted is zero, the result is positive or unsigned zero. If the value being converted is in the range of values that can be represented but the value cannot be represented exactly, it is an implementation-defined choice of either the next lower or higher representable value.
[Note: Loss of precision occurs if the integral value cannot be represented exactly as a value of the floating-point type. — end note]
If the value being converted is outside the range of values that can be represented,
the behavior is undefined.
If the source type is , the value false is converted to zero and
the value is converted to one.
Change [expr.unary.op] paragraph 8 as follows:
The operand of the unary operator shall be a prvalue of
arithmetic or unscoped enumeration type
and the result is the negative of its operand.
Integral promotion is performed on integral or enumeration operands.
The negative of an unsigned quantity is computed by subtracting its value from
,
where is the number of bits in the promoted operand.
For floating-point types that may represent negative and positive zero,
the unary operator results in the zero with opposite sign.
The type of the result is the type of the promoted operand.
Change [expr.spaceship] paragraph 4 as follows:
If both operands have arithmetic types, or one operand has integral type and the other operand has unscoped enumeration type, the usual arithmetic conversions are applied to the operands. Then:
- If a narrowing conversion ([cl.init.list]) is required, other than from an integral type to a floating-point type, the program is ill-formed.
- Otherwise, if the operands have integral type, […].
-
Otherwise, the operands have floating-point type,
and the result is of type
. The expressionstd :: partial_ordering yieldsa <=> b if a is less than b,std :: partial_ordering :: less if a is greater than b,std :: partial_ordering :: greater if a is equivalent to b, andstd :: partial_ordering :: equivalent otherwise. Positive zeros are equivalent to negative zeros.std :: partial_ordering :: unordered
Change [expr.rel] paragraph 6 as follows:
If both operands (after conversions) are of arithmetic or enumeration type,
each of the operators shall yield
if the specified relationship is and
if it is .
Positive zeros compare equal to negative zeros.
Change [expr.eq] paragraph 8 as follows:
If both operands are of arithmetic or enumeration type,
the usual arithmetic conversions ([expr.arith.conv]) are performed on both operands;
each of the operators shall yield
if the specified relationship is and
if it is .
Positive zeros compare equal to negative zeros.
[temp]
Immediately preceding [temp.type] paragraph 2, insert a new paragraph:
Two values and of a type
are bitwise identical if
([bit.cast])
is ,
where is a hypothetical unsigned integer type with the same size as and
the same amount and positioning of padding bits in its object representation as .
[Note:
It is possible that two values are the same but not bitwise identical.
For example, a floating-point type can have multiple representations
of zero,
of any other finite number,
of the same NaN value,
and more,
even if the object representation of has no padding bits.
— end note]
bitwise identical
.
Change [temp.type] paragraph 2 as follows:
Two values are template-argument-equivalent if they are of the same type and
- they are of integral type and their values are the same, or
- they are of floating-point type and their values are bitwise identical, or
- they are of type
, orstd :: nullptr_t - […]
While it would be possible to define bitwise identical
without the use of ,
the use of makes the intent obvious at first glance.
The use of unsigned
may seem unnecessary,
but it makes the wording more obvious,
and there exist integer types such as which don't behave
like the hypothetical type we want here.
[support]
Change [numeric.limits.members] as follows:
if the type has a representation for a signaling Not a Number
.
Meaningful for all floating-point types.
Shall be for all specializations in which .
[Note:
An implementation is permitted to treat all signaling NaNs as quiet NaNs,
even for types that adhere to ISO/IEC 60559 ([basic.fundamental]).
In that case, can be
despite quiet and signaling NaNs being functionally equivalent.
— end note]
for ,
despite there not existing a signaling NaN.
Paradoxically, even when there is no signaling NaN,
GCC and Clang accept the following:
The worst possible outcome would be to force implementations to report
as on WASM.
However, since the requirement for adhering to ISO/IEC 60559
in § [basic] has been relaxed,
the implementation is allowed to treat signaling NaNs as quiet NaNs,
which fixes this contradiction.
Change [cmp.alg] paragraph 2 as follows:
The name weak_order denotes a customization point object ([customization.point.object]).
Given subexpressions and ,
the expression is expression-equivalent ([defns.expression.equivalent])
to the following:
- […]
-
Otherwise, if the decayed type
ofT is a floating-point type, yields a value of typeE that is consistent with the ordering observed byweak_ordering 's comparison operators andT , and ifstrong_order isnumeric_limits < T > :: is_iec559 , is additionally consistent with the following equivalence classes, ordered from lesser to greater:true - together, all
negativeNaN values with negative sign bit; - negative infinity;
- each normal negative value;
- each subnormal negative value;
- together, both zero values;
- each subnormal positive value;
- each normal positive value;
- positive infinity;
- together, all
positiveNaN values with positive sign bit.
- together, all
- […]
negative NaN
or positive NaN
,
so the existing wording makes no sense,
especially not with the new definition of negative
.
[meta]
Change [meta.unary.prop] paragraph 10 as follows:
The predicate condition for a template specialization
shall be satisfied if and only if
is trivially copyable, andT - any two objects of type T with the same value have the same object representation, where
- two objects of array or non-union class type […]
- two objects of union type […]
The set of scalar types ([basic.fundamental]) for which this condition holds is implementation-defined.
[Example: The condition does not hold for floating-point types that adhere to ISO/IEC 60559 because there are multiple representations of the same NaN value. The condition also does not hold for any type whose object representation contains padding bits. — end example]