MathUtilsTests.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Math/MathUtils.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. using namespace AZ;
  11. namespace UnitTest
  12. {
  13. TEST(MATH_Lerp, Test)
  14. {
  15. // Float
  16. EXPECT_EQ(2.5f, AZ::Lerp(2.0f, 4.0f, 0.25f));
  17. EXPECT_EQ(6.0f, AZ::Lerp(2.0f, 4.0f, 2.0f));
  18. // Double
  19. EXPECT_EQ(3.5, AZ::Lerp(2.0, 4.0, 0.75));
  20. EXPECT_EQ(0.0, AZ::Lerp(2.0, 4.0, -1.0));
  21. }
  22. TEST(MATH_LerpInverse, Test)
  23. {
  24. // Float
  25. EXPECT_NEAR(0.25f, AZ::LerpInverse(2.0f, 4.0f, 2.5f), 0.0001f);
  26. EXPECT_NEAR(2.0f, AZ::LerpInverse(2.0f, 4.0f, 6.0f), 0.0001f);
  27. // Double
  28. EXPECT_NEAR(0.75, AZ::LerpInverse(2.0, 4.0, 3.5), 0.0001);
  29. EXPECT_NEAR(-1.0, AZ::LerpInverse(2.0, 4.0, 0.0), 0.0001);
  30. // min/max need to be substantially different to return a useful t value
  31. // Float
  32. const float epsilonF = AZStd::numeric_limits<float>::epsilon();
  33. const float doesntMatterF = AZStd::numeric_limits<float>::signaling_NaN();
  34. float lowerF = 2.3f, upperF = 2.3f;
  35. EXPECT_EQ(0.0f, AZ::LerpInverse(lowerF, upperF, doesntMatterF));
  36. EXPECT_EQ(0.0f, AZ::LerpInverse(0.0f, 0.5f * epsilonF, doesntMatterF));
  37. EXPECT_EQ(0.0f, AZ::LerpInverse(0.0f, 5.0f * epsilonF, 0.0f));
  38. EXPECT_NEAR(0.4f, AZ::LerpInverse(0.0f, 5.0f * epsilonF, 2.0f * epsilonF), epsilonF);
  39. EXPECT_NEAR(0.6f, AZ::LerpInverse(1.0f, 1.0f + 5.0f * epsilonF, 1.0f + 3.0f * epsilonF), epsilonF);
  40. EXPECT_NEAR(1.0f, AZ::LerpInverse(1.0f, 1.0f + 5.0f * epsilonF, 1.0f + 5.0f * epsilonF), epsilonF);
  41. // Double
  42. const double epsilonD = AZStd::numeric_limits<double>::epsilon();
  43. const double doesntMatterD = AZStd::numeric_limits<double>::signaling_NaN();
  44. double lowerD = 2.3, upperD = 2.3;
  45. EXPECT_EQ(0.0, AZ::LerpInverse(lowerD, upperD, doesntMatterD));
  46. EXPECT_EQ(0.0, AZ::LerpInverse(0.0, 0.5 * epsilonD, doesntMatterD));
  47. EXPECT_EQ(0.0, AZ::LerpInverse(0.0, 5.0 * epsilonD, 0.0));
  48. EXPECT_NEAR(0.4, AZ::LerpInverse(0.0, 5.0 * epsilonD, 2.0 * epsilonD), epsilonD);
  49. EXPECT_NEAR(0.6, AZ::LerpInverse(1.0, 1.0 + 5.0 * epsilonD, 1.0 + 3.0 * epsilonD), epsilonD);
  50. EXPECT_NEAR(1.0, AZ::LerpInverse(1.0, 1.0 + 5.0 * epsilonD, 1.0 + 5.0 * epsilonD), epsilonD);
  51. }
  52. template <typename T>
  53. void TestRoundUpToMultipleIsCorrect()
  54. {
  55. // Example: alignment: 4
  56. // inputValue: 0 1 2 3 4 5 6 7 8 ...
  57. // expectedOutput: 0 4 4 4 4 8 8 8 8 ...
  58. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(0) , static_cast<T>(1)) , 0);
  59. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(1) , static_cast<T>(1)) , 1);
  60. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(2) , static_cast<T>(1)) , 2);
  61. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(0) , static_cast<T>(2)) , 0);
  62. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(1) , static_cast<T>(2)) , 2);
  63. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(2) , static_cast<T>(2)) , 2);
  64. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(3) , static_cast<T>(2)) , 4);
  65. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(4) , static_cast<T>(2)) , 4);
  66. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(5) , static_cast<T>(2)) , 6);
  67. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(0) , static_cast<T>(8)) , 0);
  68. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(1) , static_cast<T>(8)) , 8);
  69. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(7) , static_cast<T>(8)) , 8);
  70. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(8) , static_cast<T>(8)) , 8);
  71. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(9) , static_cast<T>(8)) , 16);
  72. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(15), static_cast<T>(8)) , 16);
  73. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(16), static_cast<T>(8)) , 16);
  74. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(17), static_cast<T>(8)) , 24);
  75. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(0) , static_cast<T>(13)), 0);
  76. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(1) , static_cast<T>(13)), 13);
  77. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(9) , static_cast<T>(13)), 13);
  78. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(12), static_cast<T>(13)), 13);
  79. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(13), static_cast<T>(13)), 13);
  80. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(14), static_cast<T>(13)), 26);
  81. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(25), static_cast<T>(13)), 26);
  82. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(26), static_cast<T>(13)), 26);
  83. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(27), static_cast<T>(13)), 39);
  84. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(0), AZStd::numeric_limits<T>::max()), 0);
  85. T aVeryLargeNumberThatStillWontOverflow = AZStd::numeric_limits<T>::max() - 4;
  86. EXPECT_EQ(RoundUpToMultiple(static_cast<T>(1), aVeryLargeNumberThatStillWontOverflow), aVeryLargeNumberThatStillWontOverflow);
  87. EXPECT_EQ(RoundUpToMultiple(aVeryLargeNumberThatStillWontOverflow, static_cast<T>(1)), aVeryLargeNumberThatStillWontOverflow);
  88. }
  89. TEST(RoundUpToMultipleTest, RoundUpToMultipleUInt32_ValidInput_IsCorrect)
  90. {
  91. TestRoundUpToMultipleIsCorrect<uint32_t>();
  92. }
  93. TEST(RoundUpToMultipleTest, RoundUpToMultipleUInt64_ValidInput_IsCorrect)
  94. {
  95. TestRoundUpToMultipleIsCorrect<uint64_t>();
  96. }
  97. TEST(RoundUpToMultipleTest, RoundUpToMultipleSizeT_ValidInput_IsCorrect)
  98. {
  99. TestRoundUpToMultipleIsCorrect<size_t>();
  100. }
  101. template<typename T>
  102. void TestDivideAndRoundUpIsCorrect()
  103. {
  104. //! Example: alignment: 3
  105. //! Value: 0 1 2 3 4 5 6 7 8
  106. //! Result: 0 1 1 1 2 2 2 3 3
  107. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(0), static_cast<T>(3)), 0);
  108. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(1), static_cast<T>(3)), 1);
  109. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(2), static_cast<T>(3)), 1);
  110. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(3), static_cast<T>(3)), 1);
  111. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(4), static_cast<T>(3)), 2);
  112. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(5), static_cast<T>(3)), 2);
  113. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(6), static_cast<T>(3)), 2);
  114. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(7), static_cast<T>(3)), 3);
  115. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(8), static_cast<T>(3)), 3);
  116. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(0), AZStd::numeric_limits<T>::max()), 0);
  117. T aVeryLargeNumberThatStillWontOverflow = AZStd::numeric_limits<T>::max() - 4;
  118. EXPECT_EQ(DivideAndRoundUp(static_cast<T>(1), aVeryLargeNumberThatStillWontOverflow), static_cast<T>(1));
  119. EXPECT_EQ(DivideAndRoundUp(aVeryLargeNumberThatStillWontOverflow, static_cast<T>(1)), aVeryLargeNumberThatStillWontOverflow);
  120. }
  121. TEST(DivideAndRoundUpTest, DivideAndRoundUpUInt32_ValidInput_IsCorrect)
  122. {
  123. TestDivideAndRoundUpIsCorrect<uint32_t>();
  124. }
  125. TEST(DivideAndRoundUpTest, DivideAndRoundUpUInt64_ValidInput_IsCorrect)
  126. {
  127. TestDivideAndRoundUpIsCorrect<uint64_t>();
  128. }
  129. TEST(DivideAndRoundUpTest, DivideAndRoundUpSizeT_ValidInput_IsCorrect)
  130. {
  131. TestDivideAndRoundUpIsCorrect<size_t>();
  132. }
  133. // Test fixture for invalid inputs. We do not test for alignment=0
  134. // because that leads to undefined behavior with no consistent expected outcome
  135. class RoundUpInvalidInputTestsFixture : public LeakDetectionFixture
  136. {
  137. };
  138. TEST_F(RoundUpInvalidInputTestsFixture, DividAndRoundUp_OverflowUint32_Assert)
  139. {
  140. AZ_TEST_START_TRACE_SUPPRESSION;
  141. DivideAndRoundUp(
  142. static_cast<uint32_t>((AZStd::numeric_limits<uint32_t>::max() / 2) + 1),
  143. static_cast<uint32_t>((AZStd::numeric_limits<uint32_t>::max() / 2) + 1));
  144. #ifdef AZ_DEBUG_BUILD
  145. // AZ_MATH_ASSERT only asserts during debug builds, so expect an assert here
  146. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  147. #else
  148. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  149. #endif
  150. }
  151. TEST_F(RoundUpInvalidInputTestsFixture, DividAndRoundUp_OverflowUint64_Assert)
  152. {
  153. AZ_TEST_START_TRACE_SUPPRESSION;
  154. DivideAndRoundUp(
  155. static_cast<uint64_t>((AZStd::numeric_limits<uint64_t>::max() / 2) + 1),
  156. static_cast<uint64_t>((AZStd::numeric_limits<uint64_t>::max() / 2) + 1));
  157. #ifdef AZ_DEBUG_BUILD
  158. // AZ_MATH_ASSERT only asserts during debug builds, so expect an assert here
  159. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  160. #else
  161. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  162. #endif
  163. }
  164. TEST_F(RoundUpInvalidInputTestsFixture, DividAndRoundUp_OverflowSizeT_Assert)
  165. {
  166. AZ_TEST_START_TRACE_SUPPRESSION;
  167. DivideAndRoundUp(
  168. static_cast<size_t>((AZStd::numeric_limits<size_t>::max() / 2) + 1),
  169. static_cast<size_t>((AZStd::numeric_limits<size_t>::max() / 2) + 1));
  170. #ifdef AZ_DEBUG_BUILD
  171. // AZ_MATH_ASSERT only asserts during debug builds, so expect an assert here
  172. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  173. #else
  174. AZ_TEST_STOP_TRACE_SUPPRESSION(0);
  175. #endif
  176. }
  177. }