HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
onnxruntime_float16.h
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License.
3 
4 #pragma once
5 
6 #include <stdint.h>
7 #include <cmath>
8 #include <cstring>
9 #include <limits>
10 
11 namespace onnxruntime_float16 {
12 
13 namespace detail {
14 
15 enum class endian {
16 #if defined(_WIN32)
17  little = 0,
18  big = 1,
19  native = little,
20 #elif defined(__GNUC__) || defined(__clang__)
21  little = __ORDER_LITTLE_ENDIAN__,
22  big = __ORDER_BIG_ENDIAN__,
23  native = __BYTE_ORDER__,
24 #else
25 #error onnxruntime_float16::detail::endian is not implemented in this environment.
26 #endif
27 };
28 
29 static_assert(
31  "Only little-endian or big-endian native byte orders are supported.");
32 
33 } // namespace detail
34 
35 /// <summary>
36 /// Shared implementation between public and internal classes. CRTP pattern.
37 /// </summary>
38 template <class Derived>
39 struct Float16Impl {
40  protected:
41  /// <summary>
42  /// Converts from float to uint16_t float16 representation
43  /// </summary>
44  /// <param name="v"></param>
45  /// <returns></returns>
46  constexpr static uint16_t ToUint16Impl(float v) noexcept;
47 
48  /// <summary>
49  /// Converts float16 to float
50  /// </summary>
51  /// <returns>float representation of float16 value</returns>
52  float ToFloatImpl() const noexcept;
53 
54  /// <summary>
55  /// Creates an instance that represents absolute value.
56  /// </summary>
57  /// <returns>Absolute value</returns>
58  uint16_t AbsImpl() const noexcept {
59  return static_cast<uint16_t>(val & ~kSignMask);
60  }
61 
62  /// <summary>
63  /// Creates a new instance with the sign flipped.
64  /// </summary>
65  /// <returns>Flipped sign instance</returns>
66  uint16_t NegateImpl() const noexcept {
67  return IsNaN() ? val : static_cast<uint16_t>(val ^ kSignMask);
68  }
69 
70  public:
71  // uint16_t special values
72  static constexpr uint16_t kSignMask = 0x8000U;
73  static constexpr uint16_t kBiasedExponentMask = 0x7C00U;
74  static constexpr uint16_t kPositiveInfinityBits = 0x7C00U;
75  static constexpr uint16_t kNegativeInfinityBits = 0xFC00U;
76  static constexpr uint16_t kPositiveQNaNBits = 0x7E00U;
77  static constexpr uint16_t kNegativeQNaNBits = 0xFE00U;
78  static constexpr uint16_t kMaxValueBits = 0x7BFFU; // Largest normal number
79  static constexpr uint16_t kOneBits = 0x3C00U;
80  static constexpr uint16_t kMinusOneBits = 0xBC00U;
81 
82  uint16_t val{0};
83 
84  Float16Impl() = default;
85 
86  /// <summary>
87  /// Checks if the value is negative
88  /// </summary>
89  /// <returns>true if negative</returns>
90  bool IsNegative() const noexcept {
91  return static_cast<int16_t>(val) < 0;
92  }
93 
94  /// <summary>
95  /// Tests if the value is NaN
96  /// </summary>
97  /// <returns>true if NaN</returns>
98  bool IsNaN() const noexcept {
99  return AbsImpl() > kPositiveInfinityBits;
100  }
101 
102  /// <summary>
103  /// Tests if the value is finite
104  /// </summary>
105  /// <returns>true if finite</returns>
106  bool IsFinite() const noexcept {
107  return AbsImpl() < kPositiveInfinityBits;
108  }
109 
110  /// <summary>
111  /// Tests if the value represents positive infinity.
112  /// </summary>
113  /// <returns>true if positive infinity</returns>
114  bool IsPositiveInfinity() const noexcept {
115  return val == kPositiveInfinityBits;
116  }
117 
118  /// <summary>
119  /// Tests if the value represents negative infinity
120  /// </summary>
121  /// <returns>true if negative infinity</returns>
122  bool IsNegativeInfinity() const noexcept {
123  return val == kNegativeInfinityBits;
124  }
125 
126  /// <summary>
127  /// Tests if the value is either positive or negative infinity.
128  /// </summary>
129  /// <returns>True if absolute value is infinity</returns>
130  bool IsInfinity() const noexcept {
131  return AbsImpl() == kPositiveInfinityBits;
132  }
133 
134  /// <summary>
135  /// Tests if the value is NaN or zero. Useful for comparisons.
136  /// </summary>
137  /// <returns>True if NaN or zero.</returns>
138  bool IsNaNOrZero() const noexcept {
139  auto abs = AbsImpl();
140  return (abs == 0 || abs > kPositiveInfinityBits);
141  }
142 
143  /// <summary>
144  /// Tests if the value is normal (not zero, subnormal, infinite, or NaN).
145  /// </summary>
146  /// <returns>True if so</returns>
147  bool IsNormal() const noexcept {
148  auto abs = AbsImpl();
149  return (abs < kPositiveInfinityBits) // is finite
150  && (abs != 0) // is not zero
151  && ((abs & kBiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent)
152  }
153 
154  /// <summary>
155  /// Tests if the value is subnormal (denormal).
156  /// </summary>
157  /// <returns>True if so</returns>
158  bool IsSubnormal() const noexcept {
159  auto abs = AbsImpl();
160  return (abs < kPositiveInfinityBits) // is finite
161  && (abs != 0) // is not zero
162  && ((abs & kBiasedExponentMask) == 0); // is subnormal (has a zero exponent)
163  }
164 
165  /// <summary>
166  /// Creates an instance that represents absolute value.
167  /// </summary>
168  /// <returns>Absolute value</returns>
169  Derived Abs() const noexcept { return Derived::FromBits(AbsImpl()); }
170 
171  /// <summary>
172  /// Creates a new instance with the sign flipped.
173  /// </summary>
174  /// <returns>Flipped sign instance</returns>
175  Derived Negate() const noexcept { return Derived::FromBits(NegateImpl()); }
176 
177  /// <summary>
178  /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check
179  /// for two values by or'ing the private bits together and stripping the sign. They are both zero,
180  /// and therefore equivalent, if the resulting value is still zero.
181  /// </summary>
182  /// <param name="lhs">first value</param>
183  /// <param name="rhs">second value</param>
184  /// <returns>True if both arguments represent zero</returns>
185  static bool AreZero(const Float16Impl& lhs, const Float16Impl& rhs) noexcept {
186  return static_cast<uint16_t>((lhs.val | rhs.val) & ~kSignMask) == 0;
187  }
188 
189  bool operator==(const Float16Impl& rhs) const noexcept {
190  if (IsNaN() || rhs.IsNaN()) {
191  // IEEE defines that NaN is not equal to anything, including itself.
192  return false;
193  }
194  return val == rhs.val;
195  }
196 
197  bool operator!=(const Float16Impl& rhs) const noexcept { return !(*this == rhs); }
198 
199  bool operator<(const Float16Impl& rhs) const noexcept {
200  if (IsNaN() || rhs.IsNaN()) {
201  // IEEE defines that NaN is unordered with respect to everything, including itself.
202  return false;
203  }
204 
205  const bool left_is_negative = IsNegative();
206  if (left_is_negative != rhs.IsNegative()) {
207  // When the signs of left and right differ, we know that left is less than right if it is
208  // the negative value. The exception to this is if both values are zero, in which case IEEE
209  // says they should be equal, even if the signs differ.
210  return left_is_negative && !AreZero(*this, rhs);
211  }
212  return (val != rhs.val) && ((val < rhs.val) ^ left_is_negative);
213  }
214 };
215 
216 // The following Float16_t conversions are based on the code from
217 // Eigen library.
218 
219 // The conversion routines are Copyright (c) Fabian Giesen, 2016.
220 // The original license follows:
221 //
222 // Copyright (c) Fabian Giesen, 2016
223 // All rights reserved.
224 // Redistribution and use in source and binary forms, with or without
225 // modification, are permitted.
226 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
227 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
228 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
229 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
230 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
231 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
234 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
235 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
236 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
237 
238 namespace detail {
240  unsigned int u;
241  float f;
242 };
243 } // namespace detail
244 
245 template <class Derived>
246 inline constexpr uint16_t Float16Impl<Derived>::ToUint16Impl(float v) noexcept {
248  f.f = v;
249 
250  constexpr detail::float32_bits f32infty = {255 << 23};
251  constexpr detail::float32_bits f16max = {(127 + 16) << 23};
252  constexpr detail::float32_bits denorm_magic = {((127 - 15) + (23 - 10) + 1) << 23};
253  constexpr unsigned int sign_mask = 0x80000000u;
254  uint16_t val = static_cast<uint16_t>(0x0u);
255 
256  unsigned int sign = f.u & sign_mask;
257  f.u ^= sign;
258 
259  // NOTE all the integer compares in this function can be safely
260  // compiled into signed compares since all operands are below
261  // 0x80000000. Important if you want fast straight SSE2 code
262  // (since there's no unsigned PCMPGTD).
263 
264  if (f.u >= f16max.u) { // result is Inf or NaN (all exponent bits set)
265  val = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
266  } else { // (De)normalized number or zero
267  if (f.u < (113 << 23)) { // resulting FP16 is subnormal or zero
268  // use a magic value to align our 10 mantissa bits at the bottom of
269  // the float. as long as FP addition is round-to-nearest-even this
270  // just works.
271  f.f += denorm_magic.f;
272 
273  // and one integer subtract of the bias later, we have our final float!
274  val = static_cast<uint16_t>(f.u - denorm_magic.u);
275  } else {
276  unsigned int mant_odd = (f.u >> 13) & 1; // resulting mantissa is odd
277 
278  // update exponent, rounding bias part 1
279  // Equivalent to `f.u += ((unsigned int)(15 - 127) << 23) + 0xfff`, but
280  // without arithmetic overflow.
281  f.u += 0xc8000fffU;
282  // rounding bias part 2
283  f.u += mant_odd;
284  // take the bits!
285  val = static_cast<uint16_t>(f.u >> 13);
286  }
287  }
288 
289  val |= static_cast<uint16_t>(sign >> 16);
290  return val;
291 }
292 
293 template <class Derived>
294 inline float Float16Impl<Derived>::ToFloatImpl() const noexcept {
295  constexpr detail::float32_bits magic = {113 << 23};
296  constexpr unsigned int shifted_exp = 0x7c00 << 13; // exponent mask after shift
298 
299  o.u = (val & 0x7fff) << 13; // exponent/mantissa bits
300  unsigned int exp = shifted_exp & o.u; // just the exponent
301  o.u += (127 - 15) << 23; // exponent adjust
302 
303  // handle exponent special cases
304  if (exp == shifted_exp) { // Inf/NaN?
305  o.u += (128 - 16) << 23; // extra exp adjust
306  } else if (exp == 0) { // Zero/Denormal?
307  o.u += 1 << 23; // extra exp adjust
308  o.f -= magic.f; // re-normalize
309  }
310 
311  // Attempt to workaround the Internal Compiler Error on ARM64
312  // for bitwise | operator, including std::bitset
313 #if (defined _MSC_VER) && (defined _M_ARM || defined _M_ARM64 || defined _M_ARM64EC)
314  if (IsNegative()) {
315  return -o.f;
316  }
317 #else
318  // original code:
319  o.u |= (val & 0x8000U) << 16U; // sign bit
320 #endif
321  return o.f;
322 }
323 
324 /// Shared implementation between public and internal classes. CRTP pattern.
325 template <class Derived>
326 struct BFloat16Impl {
327  protected:
328  /// <summary>
329  /// Converts from float to uint16_t float16 representation
330  /// </summary>
331  /// <param name="v"></param>
332  /// <returns></returns>
333  static uint16_t ToUint16Impl(float v) noexcept;
334 
335  /// <summary>
336  /// Converts bfloat16 to float
337  /// </summary>
338  /// <returns>float representation of bfloat16 value</returns>
339  float ToFloatImpl() const noexcept;
340 
341  /// <summary>
342  /// Creates an instance that represents absolute value.
343  /// </summary>
344  /// <returns>Absolute value</returns>
345  uint16_t AbsImpl() const noexcept {
346  return static_cast<uint16_t>(val & ~kSignMask);
347  }
348 
349  /// <summary>
350  /// Creates a new instance with the sign flipped.
351  /// </summary>
352  /// <returns>Flipped sign instance</returns>
353  uint16_t NegateImpl() const noexcept {
354  return IsNaN() ? val : static_cast<uint16_t>(val ^ kSignMask);
355  }
356 
357  public:
358  // uint16_t special values
359  static constexpr uint16_t kSignMask = 0x8000U;
360  static constexpr uint16_t kBiasedExponentMask = 0x7F80U;
361  static constexpr uint16_t kPositiveInfinityBits = 0x7F80U;
362  static constexpr uint16_t kNegativeInfinityBits = 0xFF80U;
363  static constexpr uint16_t kPositiveQNaNBits = 0x7FC1U;
364  static constexpr uint16_t kNegativeQNaNBits = 0xFFC1U;
365  static constexpr uint16_t kMaxValueBits = 0x7F7FU;
366  static constexpr uint16_t kRoundToNearest = 0x7FFFU;
367  static constexpr uint16_t kOneBits = 0x3F80U;
368  static constexpr uint16_t kMinusOneBits = 0xBF80U;
369 
370  uint16_t val{0};
371 
372  BFloat16Impl() = default;
373 
374  /// <summary>
375  /// Checks if the value is negative
376  /// </summary>
377  /// <returns>true if negative</returns>
378  bool IsNegative() const noexcept {
379  return static_cast<int16_t>(val) < 0;
380  }
381 
382  /// <summary>
383  /// Tests if the value is NaN
384  /// </summary>
385  /// <returns>true if NaN</returns>
386  bool IsNaN() const noexcept {
387  return AbsImpl() > kPositiveInfinityBits;
388  }
389 
390  /// <summary>
391  /// Tests if the value is finite
392  /// </summary>
393  /// <returns>true if finite</returns>
394  bool IsFinite() const noexcept {
395  return AbsImpl() < kPositiveInfinityBits;
396  }
397 
398  /// <summary>
399  /// Tests if the value represents positive infinity.
400  /// </summary>
401  /// <returns>true if positive infinity</returns>
402  bool IsPositiveInfinity() const noexcept {
403  return val == kPositiveInfinityBits;
404  }
405 
406  /// <summary>
407  /// Tests if the value represents negative infinity
408  /// </summary>
409  /// <returns>true if negative infinity</returns>
410  bool IsNegativeInfinity() const noexcept {
411  return val == kNegativeInfinityBits;
412  }
413 
414  /// <summary>
415  /// Tests if the value is either positive or negative infinity.
416  /// </summary>
417  /// <returns>True if absolute value is infinity</returns>
418  bool IsInfinity() const noexcept {
419  return AbsImpl() == kPositiveInfinityBits;
420  }
421 
422  /// <summary>
423  /// Tests if the value is NaN or zero. Useful for comparisons.
424  /// </summary>
425  /// <returns>True if NaN or zero.</returns>
426  bool IsNaNOrZero() const noexcept {
427  auto abs = AbsImpl();
428  return (abs == 0 || abs > kPositiveInfinityBits);
429  }
430 
431  /// <summary>
432  /// Tests if the value is normal (not zero, subnormal, infinite, or NaN).
433  /// </summary>
434  /// <returns>True if so</returns>
435  bool IsNormal() const noexcept {
436  auto abs = AbsImpl();
437  return (abs < kPositiveInfinityBits) // is finite
438  && (abs != 0) // is not zero
439  && ((abs & kBiasedExponentMask) != 0); // is not subnormal (has a non-zero exponent)
440  }
441 
442  /// <summary>
443  /// Tests if the value is subnormal (denormal).
444  /// </summary>
445  /// <returns>True if so</returns>
446  bool IsSubnormal() const noexcept {
447  auto abs = AbsImpl();
448  return (abs < kPositiveInfinityBits) // is finite
449  && (abs != 0) // is not zero
450  && ((abs & kBiasedExponentMask) == 0); // is subnormal (has a zero exponent)
451  }
452 
453  /// <summary>
454  /// Creates an instance that represents absolute value.
455  /// </summary>
456  /// <returns>Absolute value</returns>
457  Derived Abs() const noexcept { return Derived::FromBits(AbsImpl()); }
458 
459  /// <summary>
460  /// Creates a new instance with the sign flipped.
461  /// </summary>
462  /// <returns>Flipped sign instance</returns>
463  Derived Negate() const noexcept { return Derived::FromBits(NegateImpl()); }
464 
465  /// <summary>
466  /// IEEE defines that positive and negative zero are equal, this gives us a quick equality check
467  /// for two values by or'ing the private bits together and stripping the sign. They are both zero,
468  /// and therefore equivalent, if the resulting value is still zero.
469  /// </summary>
470  /// <param name="lhs">first value</param>
471  /// <param name="rhs">second value</param>
472  /// <returns>True if both arguments represent zero</returns>
473  static bool AreZero(const BFloat16Impl& lhs, const BFloat16Impl& rhs) noexcept {
474  // IEEE defines that positive and negative zero are equal, this gives us a quick equality check
475  // for two values by or'ing the private bits together and stripping the sign. They are both zero,
476  // and therefore equivalent, if the resulting value is still zero.
477  return static_cast<uint16_t>((lhs.val | rhs.val) & ~kSignMask) == 0;
478  }
479 };
480 
481 template <class Derived>
482 inline uint16_t BFloat16Impl<Derived>::ToUint16Impl(float v) noexcept {
483  uint16_t result;
484  if (std::isnan(v)) {
485  result = kPositiveQNaNBits;
486  } else {
487  auto get_msb_half = [](float fl) {
488  uint16_t result;
489 #ifdef __cpp_if_constexpr
490  if constexpr (detail::endian::native == detail::endian::little) {
491 #else
492  if (detail::endian::native == detail::endian::little) {
493 #endif
494  std::memcpy(&result, reinterpret_cast<char*>(&fl) + sizeof(uint16_t), sizeof(uint16_t));
495  } else {
496  std::memcpy(&result, &fl, sizeof(uint16_t));
497  }
498  return result;
499  };
500 
501  uint16_t upper_bits = get_msb_half(v);
502  union {
503  uint32_t U32;
504  float F32;
505  };
506  F32 = v;
507  U32 += (upper_bits & 1) + kRoundToNearest;
508  result = get_msb_half(F32);
509  }
510  return result;
511 }
512 
513 template <class Derived>
514 inline float BFloat16Impl<Derived>::ToFloatImpl() const noexcept {
515  if (IsNaN()) {
516  return std::numeric_limits<float>::quiet_NaN();
517  }
518  float result;
519  char* const first = reinterpret_cast<char*>(&result);
520  char* const second = first + sizeof(uint16_t);
521 #ifdef __cpp_if_constexpr
522  if constexpr (detail::endian::native == detail::endian::little) {
523 #else
524  if (detail::endian::native == detail::endian::little) {
525 #endif
526  std::memset(first, 0, sizeof(uint16_t));
527  std::memcpy(second, &val, sizeof(uint16_t));
528  } else {
529  std::memcpy(first, &val, sizeof(uint16_t));
530  std::memset(second, 0, sizeof(uint16_t));
531  }
532  return result;
533 }
534 
535 } // namespace onnxruntime_float16
GLint first
Definition: glcorearb.h:405
static constexpr uint16_t kOneBits
bool operator<(const Float16Impl &rhs) const noexcept
bool IsNaN() const noexcept
Tests if the value is NaN
Derived Abs() const noexcept
Creates an instance that represents absolute value.
Derived Negate() const noexcept
Creates a new instance with the sign flipped.
static constexpr uint16_t kOneBits
const GLdouble * v
Definition: glcorearb.h:837
bool IsSubnormal() const noexcept
Tests if the value is subnormal (denormal).
static constexpr uint16_t kPositiveQNaNBits
bool operator!=(const Float16Impl &rhs) const noexcept
static constexpr uint16_t kNegativeInfinityBits
bool operator==(const Float16Impl &rhs) const noexcept
float ToFloatImpl() const noexcept
Converts bfloat16 to float
static bool AreZero(const Float16Impl &lhs, const Float16Impl &rhs) noexcept
IEEE defines that positive and negative zero are equal, this gives us a quick equality check for two ...
**But if you need a result
Definition: thread.h:622
bool IsNegative() const noexcept
Checks if the value is negative
static constexpr uint16_t kMaxValueBits
uint16_t NegateImpl() const noexcept
Creates a new instance with the sign flipped.
static constexpr uint16_t ToUint16Impl(float v) noexcept
Converts from float to uint16_t float16 representation
bool IsFinite() const noexcept
Tests if the value is finite
static constexpr uint16_t kBiasedExponentMask
static constexpr uint16_t kNegativeQNaNBits
bool IsPositiveInfinity() const noexcept
Tests if the value represents positive infinity.
GLfloat f
Definition: glcorearb.h:1926
bool IsNormal() const noexcept
Tests if the value is normal (not zero, subnormal, infinite, or NaN).
bool IsFinite() const noexcept
Tests if the value is finite
Shared implementation between public and internal classes. CRTP pattern.
bool IsNegative() const noexcept
Checks if the value is negative
static constexpr uint16_t kBiasedExponentMask
static constexpr uint16_t kNegativeInfinityBits
static constexpr uint16_t kMinusOneBits
bool IsNegativeInfinity() const noexcept
Tests if the value represents negative infinity
float ToFloatImpl() const noexcept
Converts float16 to float
bool IsPositiveInfinity() const noexcept
Tests if the value represents positive infinity.
static constexpr uint16_t kPositiveQNaNBits
static constexpr uint16_t kMinusOneBits
IMATH_HOSTDEVICE constexpr int sign(T a) IMATH_NOEXCEPT
Definition: ImathFun.h:33
static constexpr uint16_t kSignMask
Derived Negate() const noexcept
Creates a new instance with the sign flipped.
uint16_t AbsImpl() const noexcept
Creates an instance that represents absolute value.
bool IsNaNOrZero() const noexcept
Tests if the value is NaN or zero. Useful for comparisons.
static constexpr uint16_t kNegativeQNaNBits
bool IsInfinity() const noexcept
Tests if the value is either positive or negative infinity.
Derived Abs() const noexcept
Creates an instance that represents absolute value.
bool IsSubnormal() const noexcept
Tests if the value is subnormal (denormal).
static constexpr uint16_t kPositiveInfinityBits
static constexpr uint16_t kMaxValueBits
static constexpr uint16_t kPositiveInfinityBits
bool IsNaN() const noexcept
Tests if the value is NaN
GLuint GLfloat * val
Definition: glcorearb.h:1608
static constexpr uint16_t kRoundToNearest
static constexpr uint16_t kSignMask
bool IsNormal() const noexcept
Tests if the value is normal (not zero, subnormal, infinite, or NaN).
uint16_t AbsImpl() const noexcept
Creates an instance that represents absolute value.
bool IsNaNOrZero() const noexcept
Tests if the value is NaN or zero. Useful for comparisons.
static bool AreZero(const BFloat16Impl &lhs, const BFloat16Impl &rhs) noexcept
IEEE defines that positive and negative zero are equal, this gives us a quick equality check for two ...
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER IMATH_HOSTDEVICE constexpr T abs(T a) IMATH_NOEXCEPT
Definition: ImathFun.h:26
uint16_t NegateImpl() const noexcept
Creates a new instance with the sign flipped.
bool IsInfinity() const noexcept
Tests if the value is either positive or negative infinity.
Shared implementation between public and internal classes. CRTP pattern.
static uint16_t ToUint16Impl(float v) noexcept
Converts from float to uint16_t float16 representation
bool IsNegativeInfinity() const noexcept
Tests if the value represents negative infinity