Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
HalfFloat.h
Go to the documentation of this file.
1// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <Jolt/Math/Vec4.h>
9
11
13
14// Define half float constant values
15static constexpr HalfFloat HALF_FLT_MAX = 0x7bff;
16static constexpr HalfFloat HALF_FLT_MAX_NEGATIVE = 0xfbff;
17static constexpr HalfFloat HALF_FLT_INF = 0x7c00;
18static constexpr HalfFloat HALF_FLT_INF_NEGATIVE = 0xfc00;
19static constexpr HalfFloat HALF_FLT_NANQ = 0x7e00;
20static constexpr HalfFloat HALF_FLT_NANQ_NEGATIVE = 0xfe00;
21
23
24// Layout of a float
25static constexpr int FLOAT_SIGN_POS = 31;
26static constexpr int FLOAT_EXPONENT_POS = 23;
27static constexpr int FLOAT_EXPONENT_BITS = 8;
28static constexpr int FLOAT_EXPONENT_MASK = (1 << FLOAT_EXPONENT_BITS) - 1;
29static constexpr int FLOAT_EXPONENT_BIAS = 127;
30static constexpr int FLOAT_MANTISSA_BITS = 23;
31static constexpr int FLOAT_MANTISSA_MASK = (1 << FLOAT_MANTISSA_BITS) - 1;
32static constexpr int FLOAT_EXPONENT_AND_MANTISSA_MASK = FLOAT_MANTISSA_MASK + (FLOAT_EXPONENT_MASK << FLOAT_EXPONENT_POS);
33
34// Layout of half float
35static constexpr int HALF_FLT_SIGN_POS = 15;
36static constexpr int HALF_FLT_EXPONENT_POS = 10;
37static constexpr int HALF_FLT_EXPONENT_BITS = 5;
38static constexpr int HALF_FLT_EXPONENT_MASK = (1 << HALF_FLT_EXPONENT_BITS) - 1;
39static constexpr int HALF_FLT_EXPONENT_BIAS = 15;
40static constexpr int HALF_FLT_MANTISSA_BITS = 10;
41static constexpr int HALF_FLT_MANTISSA_MASK = (1 << HALF_FLT_MANTISSA_BITS) - 1;
42static constexpr int HALF_FLT_EXPONENT_AND_MANTISSA_MASK = HALF_FLT_MANTISSA_MASK + (HALF_FLT_EXPONENT_MASK << HALF_FLT_EXPONENT_POS);
43
51
53template <int RoundingMode>
55{
56 // Reinterpret the float as an uint32
58
59 // Extract exponent
60 uint32 exponent = (value >> FLOAT_EXPONENT_POS) & FLOAT_EXPONENT_MASK;
61
62 // Extract mantissa
63 uint32 mantissa = value & FLOAT_MANTISSA_MASK;
64
65 // Extract the sign and move it into the right spot for the half float (so we can just or it in at the end)
66 HalfFloat hf_sign = HalfFloat(value >> (FLOAT_SIGN_POS - HALF_FLT_SIGN_POS)) & (1 << HALF_FLT_SIGN_POS);
67
68 // Check NaN or INF
69 if (exponent == FLOAT_EXPONENT_MASK) // NaN or INF
70 return hf_sign | (mantissa == 0? HALF_FLT_INF : HALF_FLT_NANQ);
71
72 // Rebias the exponent for half floats
73 int rebiased_exponent = int(exponent) - FLOAT_EXPONENT_BIAS + HALF_FLT_EXPONENT_BIAS;
74
75 // Check overflow to infinity
76 if (rebiased_exponent >= HALF_FLT_EXPONENT_MASK)
77 {
79 return hf_sign | (round_up? HALF_FLT_INF : HALF_FLT_MAX);
80 }
81
82 // Check underflow to zero
83 if (rebiased_exponent < -HALF_FLT_MANTISSA_BITS)
84 {
85 bool round_up = RoundingMode != ROUND_TO_NEAREST && (hf_sign == 0) == (RoundingMode == ROUND_TO_POS_INF) && (value & FLOAT_EXPONENT_AND_MANTISSA_MASK) != 0;
86 return hf_sign | (round_up? 1 : 0);
87 }
88
90 int shift;
91 if (rebiased_exponent <= 0)
92 {
93 // Underflow to denormalized number
94 hf_exponent = 0;
95 mantissa |= 1 << FLOAT_MANTISSA_BITS; // Add the implicit 1 bit to the mantissa
96 shift = FLOAT_MANTISSA_BITS - HALF_FLT_MANTISSA_BITS + 1 - rebiased_exponent;
97 }
98 else
99 {
100 // Normal half float
101 hf_exponent = HalfFloat(rebiased_exponent << HALF_FLT_EXPONENT_POS);
102 shift = FLOAT_MANTISSA_BITS - HALF_FLT_MANTISSA_BITS;
103 }
104
105 // Compose the half float
108
109 // Calculate the remaining bits that we're discarding
110 uint remainder = mantissa & ((1 << shift) - 1);
111
112 if constexpr (RoundingMode == ROUND_TO_NEAREST)
113 {
114 // Round to nearest
115 uint round_threshold = 1 << (shift - 1);
116 if (remainder > round_threshold // Above threshold, we must always round
117 || (remainder == round_threshold && (hf_mantissa & 1))) // When equal, round to nearest even
118 hf++; // May overflow to infinity
119 }
120 else
121 {
122 // Round up or down (truncate) depending on the rounding mode
123 bool round_up = (hf_sign == 0) == (RoundingMode == ROUND_TO_POS_INF) && remainder != 0;
124 if (round_up)
125 hf++; // May overflow to infinity
126 }
127
128 return hf;
129}
130
132template <int RoundingMode>
134{
135#ifdef JPH_USE_F16C
138
139 union
140 {
142 HalfFloat u16[8];
143 } hf;
145 switch (RoundingMode)
146 {
147 case ROUND_TO_NEG_INF:
149 break;
150 case ROUND_TO_POS_INF:
152 break;
153 case ROUND_TO_NEAREST:
155 break;
156 }
157 return hf.u16[0];
158#else
160#endif
161}
162
165{
166 // Unpack half floats to 4 uint32's
168
169 // Normal half float path, extract the exponent and mantissa, shift them into place and update the exponent bias
170 UVec4 exponent_mantissa = UVec4::sAnd(value, UVec4::sReplicate(HALF_FLT_EXPONENT_AND_MANTISSA_MASK)).LogicalShiftLeft<FLOAT_EXPONENT_POS - HALF_FLT_EXPONENT_POS>() + UVec4::sReplicate((FLOAT_EXPONENT_BIAS - HALF_FLT_EXPONENT_BIAS) << FLOAT_EXPONENT_POS);
171
172 // Denormalized half float path, renormalize the float
173 UVec4 exponent_mantissa_denormalized = ((exponent_mantissa + UVec4::sReplicate(1 << FLOAT_EXPONENT_POS)).ReinterpretAsFloat() - UVec4::sReplicate((FLOAT_EXPONENT_BIAS - HALF_FLT_EXPONENT_BIAS + 1) << FLOAT_EXPONENT_POS).ReinterpretAsFloat()).ReinterpretAsInt();
174
175 // NaN / INF path, set all exponent bits
176 UVec4 exponent_mantissa_nan_inf = UVec4::sOr(exponent_mantissa, UVec4::sReplicate(FLOAT_EXPONENT_MASK << FLOAT_EXPONENT_POS));
177
178 // Get the exponent to determine which of the paths we should take
179 UVec4 exponent_mask = UVec4::sReplicate(HALF_FLT_EXPONENT_MASK << HALF_FLT_EXPONENT_POS);
183
184 // Select the correct result
186
187 // Extract the sign bit and shift it to the left
188 UVec4 sign = UVec4::sAnd(value, UVec4::sReplicate(1 << HALF_FLT_SIGN_POS)).LogicalShiftLeft<FLOAT_SIGN_POS - HALF_FLT_SIGN_POS>();
189
190 // Construct the float
192}
193
196{
197#if defined(JPH_USE_F16C)
198 return _mm_cvtph_ps(inValue.mValue);
199#elif defined(JPH_USE_NEON)
201#else
202 return ToFloatFallback(inValue);
203#endif
204}
205
206} // HalfFloatConversion
207
unsigned int uint
Definition Core.h:481
#define JPH_UNUSED(x)
Definition Core.h:573
#define JPH_NAMESPACE_END
Definition Core.h:414
std::uint32_t uint32
Definition Core.h:484
#define JPH_NAMESPACE_BEGIN
Definition Core.h:408
std::uint16_t uint16
Definition Core.h:483
uint16 HalfFloat
Definition HalfFloat.h:12
Definition FPException.h:92
Definition UVec4.h:12
JPH_INLINE UVec4 LogicalShiftLeft() const
Shift all components by Count bits to the left (filling with zeros from the left)
static JPH_INLINE UVec4 sSelect(UVec4Arg inNotSet, UVec4Arg inSet, UVec4Arg inControl)
Component wise select, returns inNotSet when highest bit of inControl = 0 and inSet when highest bit ...
Definition UVec4.inl:157
JPH_INLINE UVec4 Expand4Uint16Lo() const
Takes the lower 4 16 bits and expands them to X, Y, Z and W.
Definition UVec4.inl:463
static JPH_INLINE UVec4 sReplicate(uint32 inV)
Replicate int inV across all components.
Definition UVec4.inl:56
static JPH_INLINE UVec4 sAnd(UVec4Arg inV1, UVec4Arg inV2)
Logical and (component wise)
Definition UVec4.inl:202
static JPH_INLINE UVec4 sEquals(UVec4Arg inV1, UVec4Arg inV2)
Equals (component wise)
Definition UVec4.inl:143
static JPH_INLINE UVec4 sOr(UVec4Arg inV1, UVec4Arg inV2)
Logical or (component wise)
Definition UVec4.inl:174
static JPH_INLINE UVec4 sZero()
Vector with all zeros.
Definition UVec4.inl:45
JPH_INLINE Vec4 ReinterpretAsFloat() const
Reinterpret UVec4 as a Vec4 (doesn't change the bits)
Definition UVec4.inl:340
Definition Vec4.h:14
Definition HalfFloat.h:22
Vec4 ToFloatFallback(UVec4Arg inValue)
Convert 4 half floats (lower 64 bits) to floats, fallback version when no intrinsics available.
Definition HalfFloat.h:164
JPH_INLINE Vec4 ToFloat(UVec4Arg inValue)
Convert 4 half floats (lower 64 bits) to floats.
Definition HalfFloat.h:195
JPH_INLINE HalfFloat FromFloat(float inV)
Convert a float (32-bits) to a half float (16-bits)
Definition HalfFloat.h:133
ERoundingMode
Define half-float rounding modes.
Definition HalfFloat.h:46
@ ROUND_TO_NEG_INF
Round to negative infinity.
Definition HalfFloat.h:47
@ ROUND_TO_POS_INF
Round to positive infinity.
Definition HalfFloat.h:48
@ ROUND_TO_NEAREST
Round to nearest value.
Definition HalfFloat.h:49
HalfFloat FromFloatFallback(float inV)
Convert a float (32-bits) to a half float (16-bits), fallback version when no intrinsics available.
Definition HalfFloat.h:54