HalfFloatTests.cpp 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "UnitTestFramework.h"
  5. #include <Jolt/Math/HalfFloat.h>
  6. TEST_SUITE("HalfFloatTests")
  7. {
  8. #if defined(JPH_USE_F16C) || defined(JPH_USE_NEON)
  9. TEST_CASE("TestHalfFloatToFloat")
  10. {
  11. // Check all half float values, 4 at a time, skip NaN's and INF
  12. for (uint32 v = 0; v < 0x7c00; v += 2)
  13. {
  14. // Test value, next value and negative variants of both
  15. UVec4 half_float(v | ((v + 1) << 16), (v | 0x8000) | (((v + 1) | 0x8000) << 16), 0, 0);
  16. // Compare hardware intrinsic version with fallback version
  17. Vec4 flt1 = HalfFloatConversion::ToFloat(half_float);
  18. Vec4 flt2 = HalfFloatConversion::ToFloatFallback(half_float);
  19. UVec4 flt1_as_int = flt1.ReinterpretAsInt();
  20. UVec4 flt2_as_int = flt2.ReinterpretAsInt();
  21. if (flt1_as_int != flt2_as_int)
  22. CHECK(false); // Not using CHECK(flt1_as_int == flt2_as_int) macros as that makes the test very slow
  23. }
  24. }
  25. // Helper function to compare the intrinsics version with the fallback version
  26. static inline void CheckFloatToHalfFloat(uint32 inValue, uint32 inSign)
  27. {
  28. const float fvalue = BitCast<float>(inValue + inSign * 0x80000000U);
  29. HalfFloat hf1 = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_NEAREST>(fvalue);
  30. HalfFloat hf2 = HalfFloatConversion::FromFloatFallback<HalfFloatConversion::ROUND_TO_NEAREST>(fvalue);
  31. bool result = (hf1 == hf2);
  32. if (!result)
  33. CHECK(false); // Not using CHECK(hf1 == hf2) macros as that makes the test very slow
  34. hf1 = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_POS_INF>(fvalue);
  35. hf2 = HalfFloatConversion::FromFloatFallback<HalfFloatConversion::ROUND_TO_POS_INF>(fvalue);
  36. result = (hf1 == hf2);
  37. if (!result)
  38. CHECK(false);
  39. hf1 = HalfFloatConversion::FromFloat<HalfFloatConversion::ROUND_TO_NEG_INF>(fvalue);
  40. hf2 = HalfFloatConversion::FromFloatFallback<HalfFloatConversion::ROUND_TO_NEG_INF>(fvalue);
  41. result = (hf1 == hf2);
  42. if (!result)
  43. CHECK(false);
  44. }
  45. TEST_CASE("TestFloatToHalfFloat")
  46. {
  47. for (uint32 sign = 0; sign < 2; ++sign)
  48. {
  49. // Zero and smallest possible float
  50. for (uint32 value = 0; value < 2; value++)
  51. CheckFloatToHalfFloat(value, sign);
  52. // Floats that are large enough to become a denormalized half float, incrementing by smallest increment that can make a difference
  53. for (uint32 value = (HalfFloatConversion::FLOAT_EXPONENT_BIAS - HalfFloatConversion::HALF_FLT_EXPONENT_BIAS - HalfFloatConversion::HALF_FLT_MANTISSA_BITS) << HalfFloatConversion::FLOAT_EXPONENT_POS; value < HalfFloatConversion::FLOAT_EXPONENT_MASK << HalfFloatConversion::FLOAT_EXPONENT_POS; value += 1 << (HalfFloatConversion::FLOAT_MANTISSA_BITS - HalfFloatConversion::HALF_FLT_MANTISSA_BITS - 2))
  54. CheckFloatToHalfFloat(value, sign);
  55. // INF
  56. CheckFloatToHalfFloat(0x7f800000U, sign);
  57. // Nan
  58. CheckFloatToHalfFloat(0x7fc00000U, sign);
  59. }
  60. }
  61. #endif
  62. TEST_CASE("TestHalfFloatINF")
  63. {
  64. // Float -> half float
  65. CHECK(HalfFloatConversion::FromFloatFallback<HalfFloatConversion::ROUND_TO_NEAREST>(BitCast<float>(0x7f800000U)) == HALF_FLT_INF);
  66. CHECK(HalfFloatConversion::FromFloatFallback<HalfFloatConversion::ROUND_TO_NEAREST>(BitCast<float>(0xff800000U)) == HALF_FLT_INF_NEGATIVE);
  67. // Half float -> float
  68. UVec4 half_float(uint32(HALF_FLT_INF) | (uint32(HALF_FLT_INF_NEGATIVE) << 16), 0, 0, 0);
  69. UVec4 flt = HalfFloatConversion::ToFloatFallback(half_float).ReinterpretAsInt();
  70. CHECK(flt == UVec4(0x7f800000U, 0xff800000U, 0, 0));
  71. }
  72. TEST_CASE("TestHalfFloatNaN")
  73. {
  74. // Float -> half float
  75. CHECK(HalfFloatConversion::FromFloatFallback<HalfFloatConversion::ROUND_TO_NEAREST>(BitCast<float>(0x7fc00000U)) == HALF_FLT_NANQ);
  76. CHECK(HalfFloatConversion::FromFloatFallback<HalfFloatConversion::ROUND_TO_NEAREST>(BitCast<float>(0xffc00000U)) == HALF_FLT_NANQ_NEGATIVE);
  77. // Half float -> float
  78. UVec4 half_float(uint32(HALF_FLT_NANQ) | (uint32(HALF_FLT_NANQ_NEGATIVE) << 16), 0, 0, 0);
  79. UVec4 flt = HalfFloatConversion::ToFloatFallback(half_float).ReinterpretAsInt();
  80. CHECK(flt == UVec4(0x7fc00000U, 0xffc00000U, 0, 0));
  81. }
  82. }