ymath_ut.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include "bitops.h"
  2. #include "ymath.h"
  3. #include <library/cpp/testing/unittest/registar.h>
  4. #include <util/stream/output.h>
  5. #include <util/datetime/cputimer.h>
  6. #include <limits>
  7. template <class T>
  8. static inline T SlowClp2(T t) noexcept {
  9. Y_ASSERT(t > 0);
  10. T ret = 1;
  11. while (ret < t) {
  12. ret *= 2;
  13. }
  14. return ret;
  15. }
  16. class TMathTest: public TTestBase {
  17. UNIT_TEST_SUITE(TMathTest);
  18. UNIT_TEST(TestClp2)
  19. UNIT_TEST(TestClpSimple)
  20. UNIT_TEST(TestSqr)
  21. UNIT_TEST(TestLog2)
  22. UNIT_TEST(ValueBitCount)
  23. UNIT_TEST(TestErf);
  24. UNIT_TEST(TestLogGamma);
  25. UNIT_TEST(TestIsValidFloat);
  26. UNIT_TEST(TestAbs);
  27. UNIT_TEST(TestPower);
  28. UNIT_TEST(TestSigmoid);
  29. UNIT_TEST(TestCeilDiv);
  30. UNIT_TEST_SUITE_END();
  31. private:
  32. void TestClp2();
  33. void TestSqr();
  34. void TestErf();
  35. void TestLogGamma();
  36. void TestAbs();
  37. void TestPower();
  38. void TestSigmoid();
  39. void TestCeilDiv();
  40. inline void TestIsValidFloat() {
  41. UNIT_ASSERT(IsValidFloat(-Max<double>() / 2.));
  42. }
  43. inline void TestClpSimple() {
  44. UNIT_ASSERT_EQUAL(FastClp2<ui32>(12), 16);
  45. UNIT_ASSERT_EQUAL(FastClp2<ui16>(11), 16);
  46. UNIT_ASSERT_EQUAL(FastClp2<ui8>(10), 16);
  47. UNIT_ASSERT_EQUAL(FastClp2<ui32>(15), 16);
  48. UNIT_ASSERT_EQUAL(FastClp2<ui32>(16), 16);
  49. UNIT_ASSERT_EQUAL(FastClp2<ui32>(17), 32);
  50. }
  51. inline void TestLog2() {
  52. UNIT_ASSERT_DOUBLES_EQUAL(Log2(2.0), 1.0, 1e-10);
  53. UNIT_ASSERT_DOUBLES_EQUAL(Log2(2ull), 1.0, 1e-10);
  54. UNIT_ASSERT_DOUBLES_EQUAL(Log2(2.0f), 1.0f, 1e-7f);
  55. }
  56. inline void ValueBitCount() {
  57. UNIT_ASSERT_VALUES_EQUAL(GetValueBitCount(1), 1u);
  58. UNIT_ASSERT_VALUES_EQUAL(GetValueBitCount(2), 2u);
  59. UNIT_ASSERT_VALUES_EQUAL(GetValueBitCount(3), 2u);
  60. UNIT_ASSERT_VALUES_EQUAL(GetValueBitCount(257), 9u);
  61. }
  62. };
  63. UNIT_TEST_SUITE_REGISTRATION(TMathTest);
  64. void TMathTest::TestSqr() {
  65. UNIT_ASSERT_EQUAL(Sqr(2), 4);
  66. UNIT_ASSERT_EQUAL(Sqr(2.0), 4.0);
  67. }
  68. void TMathTest::TestClp2() {
  69. for (ui8 i = 1; i < 127; ++i) {
  70. UNIT_ASSERT_EQUAL(SlowClp2(i), FastClp2(i));
  71. }
  72. for (ui16 i = 1; i < 255; ++i) {
  73. UNIT_ASSERT_EQUAL(SlowClp2(i), FastClp2(i));
  74. }
  75. for (ui32 i = 1; i < 255; ++i) {
  76. UNIT_ASSERT_EQUAL(SlowClp2(i), FastClp2(i));
  77. }
  78. for (ui64 i = 1; i < 255; ++i) {
  79. UNIT_ASSERT_EQUAL(SlowClp2(i), FastClp2(i));
  80. }
  81. if (0) {
  82. {
  83. TFuncTimer timer("fast");
  84. size_t ret = 0;
  85. for (size_t i = 0; i < 10000000; ++i) {
  86. ret += FastClp2(i);
  87. }
  88. Cerr << ret << Endl;
  89. }
  90. {
  91. TFuncTimer timer("slow");
  92. size_t ret = 0;
  93. for (size_t i = 0; i < 10000000; ++i) {
  94. ret += SlowClp2(i);
  95. }
  96. Cerr << ret << Endl;
  97. }
  98. }
  99. }
  100. void TMathTest::TestErf() {
  101. static const double a = -5.0;
  102. static const double b = 5.0;
  103. static const int n = 50;
  104. static const double step = (b - a) / n;
  105. static const double values[n + 1] = {
  106. -1.0000000, -1.0000000, -1.0000000, -1.0000000, -1.0000000,
  107. -1.0000000, -0.9999999, -0.9999996, -0.9999985, -0.9999940,
  108. -0.9999779, -0.9999250, -0.9997640, -0.9993115, -0.9981372,
  109. -0.9953223, -0.9890905, -0.9763484, -0.9522851, -0.9103140,
  110. -0.8427008, -0.7421010, -0.6038561, -0.4283924, -0.2227026,
  111. 0.0000000,
  112. 0.2227026, 0.4283924, 0.6038561, 0.7421010, 0.8427008,
  113. 0.9103140, 0.9522851, 0.9763484, 0.9890905, 0.9953223,
  114. 0.9981372, 0.9993115, 0.9997640, 0.9999250, 0.9999779,
  115. 0.9999940, 0.9999985, 0.9999996, 0.9999999, 1.0000000,
  116. 1.0000000, 1.0000000, 1.0000000, 1.0000000, 1.0000000};
  117. double x = a;
  118. for (int i = 0; i <= n; ++i, x += step) {
  119. double f = Erf(x);
  120. UNIT_ASSERT_DOUBLES_EQUAL(f, values[i], 1e-7);
  121. }
  122. }
  123. void TMathTest::TestLogGamma() {
  124. double curVal = 0.0;
  125. for (int i = 1; i <= 20; i++) {
  126. curVal += log((double)i);
  127. UNIT_ASSERT_DOUBLES_EQUAL(curVal, LogGamma((double)(i + 1)), 1e-6);
  128. }
  129. curVal = log(M_PI) / 2.0;
  130. for (int i = 1; i <= 20; i++) {
  131. UNIT_ASSERT_DOUBLES_EQUAL(curVal, LogGamma(i - 0.5), 1e-6);
  132. curVal += log(i - 0.5);
  133. }
  134. }
  135. void TMathTest::TestAbs() {
  136. UNIT_ASSERT_VALUES_EQUAL(Abs(1), 1);
  137. UNIT_ASSERT_VALUES_EQUAL(Abs(-1), 1);
  138. UNIT_ASSERT_VALUES_EQUAL(Abs(-1000000000000ll), 1000000000000ll);
  139. UNIT_ASSERT_VALUES_EQUAL(Abs(0), 0);
  140. UNIT_ASSERT_VALUES_EQUAL(Abs(1.0), 1.0);
  141. UNIT_ASSERT_VALUES_EQUAL(Abs(-1.0), 1.0);
  142. UNIT_ASSERT_VALUES_EQUAL(Abs(0.0), 0.0);
  143. }
  144. void TMathTest::TestPower() {
  145. UNIT_ASSERT_VALUES_EQUAL(Power(0, 0), 1);
  146. UNIT_ASSERT_VALUES_EQUAL(Power(-1, 1), -1);
  147. UNIT_ASSERT_VALUES_EQUAL(Power(-1, 2), 1);
  148. UNIT_ASSERT_VALUES_EQUAL(Power(2LL, 32), 1LL << 32);
  149. UNIT_ASSERT_DOUBLES_EQUAL(Power(0.0, 0), 1.0, 1e-9);
  150. UNIT_ASSERT_DOUBLES_EQUAL(Power(0.1, 3), 1e-3, 1e-9);
  151. }
  152. void TMathTest::TestSigmoid() {
  153. UNIT_ASSERT_EQUAL(Sigmoid(0.f), 0.5f);
  154. UNIT_ASSERT_EQUAL(Sigmoid(-5000.f), 0.0f);
  155. UNIT_ASSERT_EQUAL(Sigmoid(5000.f), 1.0f);
  156. UNIT_ASSERT_EQUAL(Sigmoid(0.), 0.5);
  157. UNIT_ASSERT_EQUAL(Sigmoid(-5000.), 0.0);
  158. UNIT_ASSERT_EQUAL(Sigmoid(5000.), 1.0);
  159. }
  160. void TMathTest::TestCeilDiv() {
  161. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<ui8>(2, 3), 1);
  162. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<ui8>(3, 3), 1);
  163. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<ui32>(12, 2), 6);
  164. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<ui64>(10, 3), 4);
  165. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<ui64>(0, 10), 0);
  166. // negative numbers
  167. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(0, -10), 0);
  168. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(-1, 2), 0);
  169. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(-1, -2), 1);
  170. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(10, -5), -2);
  171. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(-3, -4), 1);
  172. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(-6, -4), 2);
  173. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(-6, 4), -1);
  174. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(-13, 4), -3);
  175. UNIT_ASSERT_VALUES_EQUAL(CeilDiv(-14, -4), 4);
  176. // check values close to overflow
  177. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<ui8>(255, 10), 26);
  178. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<ui32>(std::numeric_limits<ui32>::max() - 3, std::numeric_limits<ui32>::max()), 1);
  179. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<i32>(std::numeric_limits<i32>::max() - 3, std::numeric_limits<i32>::max()), 1);
  180. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<i32>(std::numeric_limits<i32>::min(), std::numeric_limits<i32>::max()), -1);
  181. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<i8>(std::numeric_limits<i8>::max(), std::numeric_limits<i8>::min() + 1), -1);
  182. UNIT_ASSERT_VALUES_EQUAL(CeilDiv<i64>(std::numeric_limits<i64>::max() - 2, -(std::numeric_limits<i64>::min() + 1)), 1);
  183. }