5#include "native/isa_import.h"
18#if !defined(NATIVE_HAS_NATIVE_FP16) || !defined(NATIVE_HAS_NATIVE_BF16)
19#error Configure native half capabilities before compiling native.numerics.
38 static constexpr uint16_t encode(
float value)
noexcept {
39 auto word = std::bit_cast<uint32_t>(value);
40 auto sign = (word >> 16) & 0x8000u;
41 auto a = word & 0x7fffffffu;
43 return uint16_t(sign | 0x7c00u | (a == 0x7f800000u ? 0u : 0x200u | ((a >> 13) & 0x3ffu)));
44 if (a >= 0x47800000u)
return uint16_t(sign | 0x7c00u);
46 return uint16_t(sign | (((a + 0xfffu + ((a >> 13) & 1u)) >> 13) - 0x1c000u));
47 if (a < 0x33000000u)
return uint16_t(sign);
48 auto shift = 126u - (a >> 23);
49 auto significand = (a & 0x7fffffu) | 0x800000u;
50 auto result = significand >> shift;
51 auto remainder = significand & ((1u << shift) - 1u);
52 auto half = 1u << (shift - 1u);
53 result += remainder > half || (remainder == half && (result & 1u));
54 return uint16_t(sign | result);
56 static constexpr float decode(uint16_t word)
noexcept {
57 auto sign = uint32_t(word & 0x8000u) << 16;
58 auto exponent = (word >> 10) & 31u;
59 auto fraction = uint32_t(word & 0x3ffu);
62 if (fraction == 0)
return std::bit_cast<float>(sign);
63 auto shift = unsigned(std::countl_zero(fraction)) - 21u;
64 result = ((113u - shift) << 23) | (((fraction << shift) & 0x3ffu) << 13);
65 }
else if (exponent == 31) {
66 result = 0x7f800000u | (fraction << 13) | (fraction ? 0x400000u : 0u);
67 }
else result = ((exponent + 112u) << 23) | (fraction << 13);
68 return std::bit_cast<float>(sign | result);
72#if NATIVE_HAS_NATIVE_FP16
83 constexpr fp16() noexcept = default;
97#if NATIVE_HAS_NATIVE_FP16
105 constexpr operator float (
this fp16 self)
noexcept {
return decode(self.to_bits()); }
107#if NATIVE_HAS_NATIVE_FP16
110 constexpr operator _Float16 (
this fp16 self)
noexcept {
return self.content; }
125 friend constexpr
bool operator == (
fp16 x,
fp16 y) noexcept {
126 return static_cast<float>(x) ==
static_cast<float>(y);
132 return static_cast<float>(x) !=
static_cast<float>(y);
138 return static_cast<float>(x) <=>
static_cast<float>(y);
144 return static_cast<float>(x) <
static_cast<float>(y);
150 return static_cast<float>(x) <=
static_cast<float>(y);
155 return static_cast<float>(x) >
static_cast<float>(y);
161 return static_cast<float>(x) >=
static_cast<float>(y);
171 swap(x.content,y.content);
177 return std::bit_cast<fp16>(data);
183 return std::bit_cast<uint16_t>(self.content);
194constexpr fp16 operator""_fp16(
long double v)
noexcept {
195 return fp16(
static_cast<float>(v));
202export namespace std {
203 using ::std::numeric_limits;
208 return (x.to_bits() & 0x7FFF) > 0x7c00;
216 static constexpr bool is_specialized =
true;
219 static constexpr ::native::fp16
min() noexcept {
220 return ::native::fp16::from_bits(0x0400);
224 static constexpr ::native::fp16
max() noexcept {
225 return ::native::fp16::from_bits(0x7BFF);
229 static constexpr ::native::fp16
lowest() noexcept {
230 return ::native::fp16::from_bits(0xFBFF);
232 static constexpr int digits = 11;
233 static constexpr int digits10 = 3;
234 static constexpr int max_digits10 = 5;
235 static constexpr bool is_signed =
true;
236 static constexpr bool is_integer =
false;
237 static constexpr bool is_exact =
false;
238 static constexpr int radix = 2;
241 static constexpr ::native::fp16
epsilon() noexcept {
242 return ::native::fp16::from_bits(0x1400);
247 return ::native::fp16::from_bits(0x3800);
249 static constexpr int min_exponent = -13;
250 static constexpr int min_exponent10 = -4;
251 static constexpr int max_exponent = 16;
252 static constexpr int max_exponent10 = 4;
253 static constexpr bool has_infinity =
true;
254 static constexpr bool has_quiet_NaN =
true;
255 static constexpr bool has_signaling_NaN =
true;
256 [[deprecated(
"std::float_denorm_style is deprecated since C++23")]]
257 static constexpr float_denorm_style
has_denorm = denorm_present;
258 [[deprecated(
"numeric_limits::has_denorm_loss is deprecated since C++23")]]
262 static constexpr ::native::fp16
infinity() noexcept {
263 return ::native::fp16::from_bits(0x7C00);
268 return ::native::fp16::from_bits(0x7FFF);
273 return ::native::fp16::from_bits(0x7DFF);
278 return ::native::fp16::from_bits(1);
280 static constexpr bool is_iec559 =
false;
281 static constexpr bool is_bounded =
true;
282 static constexpr bool is_modulo =
false;
283 static constexpr bool traps =
false;
284 static constexpr bool tinyness_before =
false;
285 static constexpr float_round_style round_style = round_to_nearest;
303 static constexpr uint16_t encode(
float value)
noexcept {
304 auto word = std::bit_cast<uint32_t>(value);
305 if ((word & 0x7fffffffu) > 0x7f800000u)
306 return uint16_t((word >> 16) | 0x40u);
307 return uint16_t((word + 0x7fffu + ((word >> 16) & 1u)) >> 16);
309 static constexpr float decode(uint16_t word)
noexcept {
310 auto result = uint32_t(word) << 16;
311 if ((word & 0x7fffu) > 0x7f80u) result |= 0x400000u;
312 return std::bit_cast<float>(result);
316#if NATIVE_HAS_NATIVE_BF16
333#if NATIVE_HAS_NATIVE_BF16
347#if NATIVE_HAS_NATIVE_BF16
350 operator __bf16 (
this bf16 self)
noexcept {
return self.content; }
355 operator float (
this bf16 self)
noexcept {
return decode(self.to_bits()); }
369 friend constexpr
bool operator == (
bf16 x,
bf16 y) noexcept {
370 return static_cast<float>(x) ==
static_cast<float>(y);
376 return static_cast<float>(x) <=>
static_cast<float>(y);
382 return static_cast<float>(x) !=
static_cast<float>(y);
388 return static_cast<float>(x) <
static_cast<float>(y);
394 return static_cast<float>(x) >
static_cast<float>(y);
400 return static_cast<float>(x) <=
static_cast<float>(y);
406 return static_cast<float>(x) >=
static_cast<float>(y);
416 swap(x.content,y.content);
422 return std::bit_cast<bf16>(data);
428 return std::bit_cast<uint16_t>(self.content);
438constexpr bf16 operator""_bf16(
long double v)
noexcept {
439 return bf16(
static_cast<float>(v));
450 return std::bit_cast<bf16>(
static_cast<uint16_t
>(std::bit_cast<uint32_t>(f)>>16));
462export namespace std {
463 using ::std::numeric_limits;
468 return (x.to_bits() & 0x7FFF) > 0x7F80;
475 static constexpr bool is_specialized =
true;
478 static constexpr ::native::bf16
min() noexcept {
479 return ::native::bf16::from_bits(0x0080);
483 static constexpr ::native::bf16
max() noexcept {
484 return ::native::bf16::from_bits(0x7F7F);
488 static constexpr ::native::bf16
lowest() noexcept {
489 return ::native::bf16::from_bits(0xFF7F);
491 static constexpr int digits = 8;
492 static constexpr int digits10 = 2;
493 static constexpr int max_digits10 = 4;
494 static constexpr bool is_signed =
true;
495 static constexpr bool is_integer =
false;
496 static constexpr bool is_exact =
false;
497 static constexpr int radix = 2;
500 static constexpr ::native::bf16
epsilon() noexcept {
501 return ::native::bf16::from_bits(0x3C00);
506 return ::native::bf16::from_bits(0x3F00);
508 static constexpr int min_exponent = -125;
509 static constexpr int min_exponent10 = -37;
510 static constexpr int max_exponent = 128;
511 static constexpr int max_exponent10 = 38;
512 static constexpr bool has_infinity =
true;
513 static constexpr bool has_quiet_NaN =
true;
514 static constexpr bool has_signaling_NaN =
true;
515 [[deprecated(
"std::float_denorm_style is deprecated since C++23")]]
516 static constexpr float_denorm_style
has_denorm = denorm_present;
517 [[deprecated(
"numeric_limits::has_denorm_loss is deprecated since C++23")]]
521 static constexpr ::native::bf16
infinity() noexcept {
522 return ::native::bf16::from_bits(0x7F80);
527 return ::native::bf16::from_bits(0x7FC0);
532 return ::native::bf16::from_bits(0x7F81);
537 return ::native::bf16::from_bits(1);
539 static constexpr bool is_iec559 =
false;
540 static constexpr bool is_bounded =
true;
541 static constexpr bool is_modulo =
false;
542 static constexpr bool traps =
false;
543 static constexpr bool tinyness_before =
false;
544 static constexpr float_round_style round_style = round_to_nearest;
555 using ::native::imm_t;
561template <
auto N,
auto ... candidates>
562concept one_of = ((N==candidates) || ... ||
false);
565template <
auto N,
auto ... candidates>
569template <std::
size_t N>
struct integer_traits {};
570template <>
struct integer_traits<8> {
using signed_t = int8_t;
using unsigned_t = uint8_t; };
571template <>
struct integer_traits<16> {
using signed_t = int16_t;
using unsigned_t = uint16_t; };
572template <>
struct integer_traits<32> {
using signed_t = int32_t;
using unsigned_t = uint32_t; };
573template <>
struct integer_traits<64> {
using signed_t = int64_t;
using unsigned_t = uint64_t; };
579requires one_of<
sizeof(T),1,2,4,8>
580using int_t =
typename integer_traits<
sizeof(T)*8>::signed_t;
585requires one_of<
sizeof(T),1,2,4,8>
586using uint_t =
typename integer_traits<
sizeof(T)*8>::unsigned_t;
632template <one_of_t<
float,
double> T>
637 constexpr int fraction_bits = std::numeric_limits<T>::digits - 1;
638 constexpr int bias = std::numeric_limits<T>::max_exponent - 1;
639 constexpr U hidden = U(1) << fraction_bits;
640 constexpr U sign_mask = U(1) << (
sizeof(T) * 8 - 1);
641 constexpr U exponent_mask = U(2 * bias + 1) << fraction_bits;
642 auto const word = std::bit_cast<U>(x);
643 auto const sign = word & sign_mask;
644 auto const field = (word & exponent_mask) >> fraction_bits;
645 auto significand = word & (hidden - 1);
646 if (field == U(2 * bias + 1) || (field == 0 && significand == 0))
return x;
647 int const scale =
static_cast<int>(y);
651 if constexpr (
requires {
652 typename std::enable_if_t<
653 std::scalbn(T(1), 1 - bias) == std::numeric_limits<T>::min() &&
654 std::scalbn(T(1), 1 - bias - fraction_bits) == std::numeric_limits<T>::denorm_min() &&
655 std::scalbn(T(-1), bias + 1) == -std::numeric_limits<T>::infinity() &&
656 std::bit_cast<U>(std::scalbn(T(-1), -bias - fraction_bits)) == sign_mask &&
657 std::scalbn(T(1), std::numeric_limits<int>::min()) == T(0) &&
658 std::scalbn(T(1), std::numeric_limits<int>::max()) == std::numeric_limits<T>::infinity()>;
660 return std::scalbn(x, scale);
663 std::int64_t exponent = field ? std::int64_t(field) - bias : 1 - bias;
664 if (field) significand |= hidden;
665 else while (significand < hidden) { significand <<= 1; --exponent; }
667 if (exponent > bias)
return std::bit_cast<T>(sign | exponent_mask);
668 if (exponent >= 1 - bias) {
669 return std::bit_cast<T>(sign | (U(exponent + bias) << fraction_bits) |
670 (significand & (hidden - 1)));
672 auto const shift = (1 - bias) - exponent;
673 if (shift > fraction_bits + 1)
return std::bit_cast<T>(sign);
674 U
const remainder = significand & ((U(1) << shift) - 1);
675 U
const halfway = U(1) << (shift - 1);
676 U rounded = significand >> shift;
677 rounded += remainder > halfway || (remainder == halfway && (rounded & 1));
679 return std::bit_cast<T>(sign | rounded);
682 return std::scalbn(x,
static_cast<int>(y));
702template <CMPINT imm8,
typename T>
703requires (one_of_t<T, uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t> && (std::size_t(imm8) < 8uz))
705constexpr bool cmpint(T a, T b)
noexcept {
707 if constexpr (imm8 ==
TRUE)
return -1;
708 else if constexpr (imm8 ==
FALSE)
return 0;
709 else if constexpr (imm8 ==
LT)
return a < b;
710 else if constexpr (imm8 ==
NLT)
return a >= b;
711 else if constexpr (imm8 ==
LE)
return a <= b;
712 else if constexpr (imm8 ==
NLE)
return a > b;
713 else if constexpr (imm8 ==
EQ)
return a == b;
714 else if constexpr (imm8 ==
NE)
return a != b;
715 else static_assert(
false);
772template <CMP imm8,
typename T>
773requires (one_of_t<T, float, double> && (std::size_t(imm8) < 32uz))
775constexpr bool cmp(T a, T b)
noexcept {
777 if constexpr (imm8 ==
EQ_OQ)
return cmp_ord(a, b) && (a == b);
778 else if constexpr (imm8 ==
LT_OS)
return cmp_ord(a, b) && (a < b);
779 else if constexpr (imm8 ==
LE_OS)
return cmp_ord(a, b) && (a <= b);
783 else if constexpr (imm8 ==
NLE_US)
return cmp_unord(a, b) || !(a <= b);
785 else if constexpr (imm8 ==
EQ_UQ)
return cmp_unord(a, b) || (a == b);
786 else if constexpr (imm8 ==
NGE_US)
return cmp_unord(a, b) || !(a >= b);
788 else if constexpr (imm8 ==
FALSE_OQ)
return 0;
789 else if constexpr (imm8 ==
NEQ_OQ)
return cmp_ord(a, b) && (a != b);
790 else if constexpr (imm8 ==
GE_OS)
return cmp_ord(a, b) && (a >= b);
791 else if constexpr (imm8 ==
GT_OS)
return cmp_ord(a, b) && (a > b);
792 else if constexpr (imm8 ==
TRUE_UQ)
return -1;
793 else if constexpr (imm8 ==
EQ_OS)
return cmp_ord(a, b) && (a == b);
794 else if constexpr (imm8 ==
LT_OQ)
return cmp_ord(a, b) && (a < b);
795 else if constexpr (imm8 ==
LE_OQ)
return cmp_ord(a, b) && (a <= b);
799 else if constexpr (imm8 ==
NLE_UQ)
return cmp_unord(a, b) || !(a <= b);
801 else if constexpr (imm8 ==
EQ_US)
return cmp_unord(a, b) || (a == b);
802 else if constexpr (imm8 ==
NGE_UQ)
return cmp_unord(a, b) || !(a >= b);
804 else if constexpr (imm8 ==
FALSE_OS)
return 0;
805 else if constexpr (imm8 ==
NEQ_OS)
return cmp_ord(a, b) && (a != b);
806 else if constexpr (imm8 ==
GE_OQ)
return cmp_ord(a, b) && (a >= b);
807 else if constexpr (imm8 ==
GT_OQ)
return cmp_ord(a, b) && (a > b);
808 else if constexpr (imm8 ==
TRUE_US)
return -1;
809 else static_assert(
false);
830 template float scalef(
float,
float)
noexcept;
833 template double scalef(
double,
double)
noexcept;
Compiler attributes for host code, with shader-safe shared modifiers.
static constexpr ::native::bf16 epsilon() noexcept
Return the distance from one to its successor, 2^-7 (bits 0x3c00).
static constexpr float_denorm_style has_denorm
static constexpr ::native::bf16 min() noexcept
Return the least positive normal value, 2^-126 (bits 0x0080).
static constexpr ::native::bf16 denorm_min() noexcept
Return the least positive subnormal value, 2^-133 (bits 0x0001).
static constexpr ::native::bf16 max() noexcept
Return the greatest finite value, (2 - 2^-7) * 2^127 (bits 0x7f7f).
static constexpr ::native::bf16 quiet_NaN() noexcept
Return a quiet NaN with the fixed encoding 0x7fc0.
static constexpr ::native::bf16 round_error() noexcept
Return the round-to-nearest error bound, one half (bits 0x3f00).
static constexpr bool has_denorm_loss
static constexpr ::native::bf16 signaling_NaN() noexcept
Return a signaling NaN encoding (bits 0x7f81); decoding to float quiets it.
static constexpr ::native::bf16 infinity() noexcept
Return positive infinity (bits 0x7f80).
static constexpr ::native::bf16 lowest() noexcept
Return the negative of max() (bits 0xff7f).
static constexpr ::native::fp16 round_error() noexcept
Return the round-to-nearest error bound, one half (bits 0x3800).
static constexpr ::native::fp16 min() noexcept
Return the least positive normal value, 2^-14 (bits 0x0400).
static constexpr ::native::fp16 max() noexcept
Return the greatest finite value, 65504 (bits 0x7bff).
static constexpr ::native::fp16 infinity() noexcept
Return positive infinity (bits 0x7c00).
static constexpr ::native::fp16 denorm_min() noexcept
Return the least positive subnormal value, 2^-24 (bits 0x0001).
static constexpr ::native::fp16 quiet_NaN() noexcept
Return a quiet NaN with the fixed encoding 0x7fff.
static constexpr bool has_denorm_loss
static constexpr ::native::fp16 signaling_NaN() noexcept
Return a signaling NaN encoding (bits 0x7dff); decoding to float quiets it.
static constexpr float_denorm_style has_denorm
static constexpr ::native::fp16 epsilon() noexcept
Return the distance from one to its successor, 2^-10 (bits 0x1400).
static constexpr ::native::fp16 lowest() noexcept
Return the most negative finite value, -65504 (bits 0xfbff).
Declares SIMD element types and pointer access policies.
N is not one of the candidates
N is one of the candidates
#define native_reinitializes
[[clang::reinitializes]]
#define native_artificial
[[artificial]].
#define native_inline
inline [[always_inline]]
#define native_noescape
portable __attribute__((noescape))
#define native_nodiscard
C++17 [[nodiscard]].
#define native_lifetimebound
[[lifetimebound]]
constexpr bool cmp_ord(T a, T b) noexcept(noexcept(!isnan(a) &&!isnan(b)))
Return true if neither argument is NaN.
constexpr std::size_t max_fp_comparison_predicate
constexpr T scalef(T x, T y) noexcept
typename integer_traits< sizeof(T) *8 >::unsigned_t uint_t
constexpr bool cmpint(T a, T b) noexcept
typename integer_traits< sizeof(T) *8 >::signed_t int_t
constexpr bool cmp(T a, T b) noexcept
CMP
Scalar floating-comparison predicates, including ordered and unordered truth tables.
CMPINT
Scalar integer-comparison predicates, encoded like the corresponding x86 immediates.
constexpr bool cmp_unord(T a, T b) noexcept(noexcept(isnan(a)||isnan(b)))
Return true if either argument is NaN.
@ LE_OQ
Less-than-or-equal (ordered, nonsignaling).
@ FALSE_OQ
False (ordered, nonsignaling).
@ NEQ_OS
Not-equal (ordered, signaling).
@ NLE_US
Not-less-than-or-equal (unordered, signaling).
@ TRUE_US
True (unordered, signaling).
@ NGE_UQ
Not-greater-than-or-equal (unordered, nonsignaling).
@ GE_OS
Greater-than-or-equal (ordered, signaling).
@ NEQ_OQ
Not-equal (ordered, nonsignaling).
@ ORD_Q
Ordered (nonsignaling).
@ LT_OS
Less-than (ordered, signaling).
@ GE_OQ
Greater-than-or-equal (ordered, nonsignaling).
@ EQ_US
Equal (unordered, signaling).
@ TRUE_UQ
True (unordered, nonsignaling).
@ EQ_OS
Equal (ordered, signaling).
@ FALSE_OS
False (ordered, signaling).
@ GT_OS
Greater-than (ordered, signaling).
@ ORD_S
Ordered (signaling).
@ NLE_UQ
Not-less-than-or-equal (unordered, nonsignaling).
@ GT_OQ
Greater-than (ordered, nonsignaling).
@ UNORD_S
Unordered (signaling).
@ LE_OS
Less-than-or-equal (ordered, signaling).
@ EQ_OQ
Equal (ordered, nonsignaling).
@ NEQ_UQ
Not-equal (unordered, nonsignaling).
@ EQ_UQ
Equal (unordered, nonsignaling).
@ NLT_US
Not-less-than (unordered, signaling).
@ UNORD_Q
Unordered (nonsignaling).
@ LT_OQ
Less-than (ordered, nonsignaling).
@ NLT_UQ
Not-less-than (unordered, nonsignaling).
@ NGT_US
Not-greater-than (unordered, signaling).
@ NGE_US
Not-greater-than-or-equal (unordered, signaling).
@ NGT_UQ
Not-greater-than (unordered, nonsignaling).
@ NEQ_US
Not-equal (unordered, signaling).
#define native_const
[[const]] is not const
#define native_pure
[[pure]]
constexpr auto isnan(wide< T, N > const &input) noexcept(noexcept(detail::wide_generic_detail::wide_map< detail::wide_generic_detail::wide_isnan >(input)))
Scalar half storage, numeric limits and legacy scalar predicates.
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
constexpr bf16 fast_to_bf16(float f) noexcept
Standard-library adaptations documented here for SIMD value types.
constexpr bool isnan(::native::fp16 x) noexcept
Classify the stored bits as NaN without performing a floating-point conversion.
friend constexpr bool operator<(bf16 x, bf16 y) noexcept
Return whether the decoded left value is less; false for NaN operands.
constexpr uint16_t to_bits(this bf16 self) noexcept
Return the exact sixteen representation bits.
friend constexpr std::partial_ordering operator<=>(bf16 x, bf16 y) noexcept
Compare decoded values; NaNs are unordered and signed zeros equivalent.
constexpr bf16(bf16 &&) noexcept=default
Copy the native representation; the source retains its bits.
friend constexpr bool operator<=(bf16 x, bf16 y) noexcept
Return whether the decoded left value is at most the right; false for NaN operands.
constexpr bf16(__bf16 f) noexcept
Copy native storage without a numerical conversion.
constexpr bf16(bf16 const &) noexcept=default
Copy the native sixteen-bit representation.
friend constexpr bool operator>=(bf16 x, bf16 y) noexcept
Return whether the decoded left value is at least the right; false for NaN operands.
underlying_type content
Target-dependent storage. Use to_bits()/from_bits() for portable representation access.
friend constexpr bool operator!=(bf16 x, bf16 y) noexcept
Compare decoded values for inequality; a NaN operand makes the result true.
friend constexpr bool operator>(bf16 x, bf16 y) noexcept
Return whether the decoded left value is greater; false for NaN operands.
static constexpr bf16 from_bits(uint16_t data) noexcept
Adopt the exact sixteen representation bits without normalization.
friend constexpr void swap(bf16 &x, bf16 &y) noexcept
Exchange native representations, including signed zeros and NaN payloads.
constexpr bf16 & operator=(bf16 const &) noexcept=default
Copy the native representation, replacing all previous bits.
__bf16 underlying_type
Native half storage when supported by the target; otherwise sixteen raw bits.
constexpr bf16() noexcept=default
Default-initialize storage without setting its bits; value-initialization zeroes it.
friend constexpr std::partial_ordering operator<=>(fp16 x, fp16 y) noexcept
Compare decoded values; NaNs are unordered and signed zeros equivalent.
_Float16 underlying_type
Native half storage when supported by the target; otherwise sixteen raw bits.
constexpr fp16 & operator=(fp16 const &) noexcept=default
Copy the native representation, replacing all previous bits.
friend constexpr bool operator<(fp16 x, fp16 y) noexcept
Return whether the decoded left value is less; false for NaN operands.
constexpr uint16_t to_bits(this fp16 self) noexcept
Return the exact sixteen representation bits.
constexpr fp16(_Float16 content) noexcept
Copy native storage without a numerical conversion.
friend constexpr bool operator<=(fp16 x, fp16 y) noexcept
Return whether the decoded left value is at most the right; false for NaN operands.
static constexpr fp16 from_bits(uint16_t data) noexcept
Adopt the exact sixteen representation bits without normalization.
friend constexpr bool operator>=(fp16 x, fp16 y) noexcept
Return whether the decoded left value is at least the right; false for NaN operands.
underlying_type content
Target-dependent storage. Use to_bits()/from_bits() for portable representation access.
friend constexpr bool operator!=(fp16 x, fp16 y) noexcept
Compare decoded values for inequality; a NaN operand makes the result true.
friend constexpr bool operator>(fp16 x, fp16 y) noexcept
Return whether the decoded left value is greater; false for NaN operands.
constexpr fp16() noexcept=default
Default-initialize storage without setting its bits; value-initialization zeroes it.
friend constexpr void swap(fp16 &x, fp16 &y) noexcept
Exchange native representations, including signed zeros and NaN payloads.