MathTest.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Copyright 2016-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/Math.h>
  17. #include <algorithm>
  18. #include <type_traits>
  19. #include <utility>
  20. #include <vector>
  21. #include <glog/logging.h>
  22. #include <folly/Portability.h>
  23. #include <folly/portability/GTest.h>
  24. using namespace folly;
  25. using namespace folly::detail;
  26. namespace {
  27. // Workaround for https://llvm.org/bugs/show_bug.cgi?id=16404,
  28. // issues with __int128 multiplication and UBSAN
  29. template <typename T>
  30. T mul(T lhs, T rhs) {
  31. if (rhs < 0) {
  32. rhs = -rhs;
  33. lhs = -lhs;
  34. }
  35. T accum = 0;
  36. while (rhs != 0) {
  37. if ((rhs & 1) != 0) {
  38. accum += lhs;
  39. }
  40. lhs += lhs;
  41. rhs >>= 1;
  42. }
  43. return accum;
  44. }
  45. template <typename T, typename B>
  46. T referenceDivFloor(T numer, T denom) {
  47. // rv = largest integral value <= numer / denom
  48. B n = numer;
  49. B d = denom;
  50. if (d < 0) {
  51. d = -d;
  52. n = -n;
  53. }
  54. B r = n / d;
  55. while (mul(r, d) > n) {
  56. --r;
  57. }
  58. while (mul(r + 1, d) <= n) {
  59. ++r;
  60. }
  61. T rv = static_cast<T>(r);
  62. assert(static_cast<B>(rv) == r);
  63. return rv;
  64. }
  65. template <typename T, typename B>
  66. T referenceDivCeil(T numer, T denom) {
  67. // rv = smallest integral value >= numer / denom
  68. B n = numer;
  69. B d = denom;
  70. if (d < 0) {
  71. d = -d;
  72. n = -n;
  73. }
  74. B r = n / d;
  75. while (mul(r, d) < n) {
  76. ++r;
  77. }
  78. while (mul(r - 1, d) >= n) {
  79. --r;
  80. }
  81. T rv = static_cast<T>(r);
  82. assert(static_cast<B>(rv) == r);
  83. return rv;
  84. }
  85. template <typename T, typename B>
  86. T referenceDivRoundAway(T numer, T denom) {
  87. if ((numer < 0) != (denom < 0)) {
  88. return referenceDivFloor<T, B>(numer, denom);
  89. } else {
  90. return referenceDivCeil<T, B>(numer, denom);
  91. }
  92. }
  93. template <typename T>
  94. std::vector<T> cornerValues() {
  95. std::vector<T> rv;
  96. for (T i = 1; i < 24; ++i) {
  97. rv.push_back(i);
  98. rv.push_back(T(std::numeric_limits<T>::max() / i));
  99. rv.push_back(T(std::numeric_limits<T>::max() - i));
  100. rv.push_back(T(std::numeric_limits<T>::max() / T(2) - i));
  101. if (std::is_signed<T>::value) {
  102. rv.push_back(-i);
  103. rv.push_back(T(std::numeric_limits<T>::min() / i));
  104. rv.push_back(T(std::numeric_limits<T>::min() + i));
  105. rv.push_back(T(std::numeric_limits<T>::min() / T(2) + i));
  106. }
  107. }
  108. return rv;
  109. }
  110. template <typename A, typename B, typename C>
  111. void runDivTests() {
  112. using T = decltype(static_cast<A>(1) / static_cast<B>(1));
  113. auto numers = cornerValues<A>();
  114. numers.push_back(0);
  115. auto denoms = cornerValues<B>();
  116. for (A n : numers) {
  117. for (B d : denoms) {
  118. if (std::is_signed<T>::value && n == std::numeric_limits<T>::min() &&
  119. d == static_cast<T>(-1)) {
  120. // n / d overflows in two's complement
  121. continue;
  122. }
  123. EXPECT_EQ(divCeil(n, d), (referenceDivCeil<T, C>(n, d))) << n << "/" << d;
  124. EXPECT_EQ(divFloor(n, d), (referenceDivFloor<T, C>(n, d)))
  125. << n << "/" << d;
  126. EXPECT_EQ(divTrunc(n, d), n / d) << n << "/" << d;
  127. EXPECT_EQ(divRoundAway(n, d), (referenceDivRoundAway<T, C>(n, d)))
  128. << n << "/" << d;
  129. T nn = n;
  130. T dd = d;
  131. EXPECT_EQ(divCeilBranchless(nn, dd), divCeilBranchful(nn, dd));
  132. EXPECT_EQ(divFloorBranchless(nn, dd), divFloorBranchful(nn, dd));
  133. EXPECT_EQ(divRoundAwayBranchless(nn, dd), divRoundAwayBranchful(nn, dd));
  134. }
  135. }
  136. }
  137. } // namespace
  138. TEST(Bits, divTestInt8) {
  139. runDivTests<int8_t, int8_t, int64_t>();
  140. runDivTests<int8_t, uint8_t, int64_t>();
  141. runDivTests<int8_t, int16_t, int64_t>();
  142. runDivTests<int8_t, uint16_t, int64_t>();
  143. runDivTests<int8_t, int32_t, int64_t>();
  144. runDivTests<int8_t, uint32_t, int64_t>();
  145. #if FOLLY_HAVE_INT128_T
  146. runDivTests<int8_t, int64_t, __int128>();
  147. runDivTests<int8_t, uint64_t, __int128>();
  148. #endif
  149. }
  150. TEST(Bits, divTestInt16) {
  151. runDivTests<int16_t, int8_t, int64_t>();
  152. runDivTests<int16_t, uint8_t, int64_t>();
  153. runDivTests<int16_t, int16_t, int64_t>();
  154. runDivTests<int16_t, uint16_t, int64_t>();
  155. runDivTests<int16_t, int32_t, int64_t>();
  156. runDivTests<int16_t, uint32_t, int64_t>();
  157. #if FOLLY_HAVE_INT128_T
  158. runDivTests<int16_t, int64_t, __int128>();
  159. runDivTests<int16_t, uint64_t, __int128>();
  160. #endif
  161. }
  162. TEST(Bits, divTestInt32) {
  163. runDivTests<int32_t, int8_t, int64_t>();
  164. runDivTests<int32_t, uint8_t, int64_t>();
  165. runDivTests<int32_t, int16_t, int64_t>();
  166. runDivTests<int32_t, uint16_t, int64_t>();
  167. runDivTests<int32_t, int32_t, int64_t>();
  168. runDivTests<int32_t, uint32_t, int64_t>();
  169. #if FOLLY_HAVE_INT128_T
  170. runDivTests<int32_t, int64_t, __int128>();
  171. runDivTests<int32_t, uint64_t, __int128>();
  172. #endif
  173. }
  174. #if FOLLY_HAVE_INT128_T
  175. TEST(Bits, divTestInt64) {
  176. runDivTests<int64_t, int8_t, __int128>();
  177. runDivTests<int64_t, uint8_t, __int128>();
  178. runDivTests<int64_t, int16_t, __int128>();
  179. runDivTests<int64_t, uint16_t, __int128>();
  180. runDivTests<int64_t, int32_t, __int128>();
  181. runDivTests<int64_t, uint32_t, __int128>();
  182. runDivTests<int64_t, int64_t, __int128>();
  183. runDivTests<int64_t, uint64_t, __int128>();
  184. }
  185. #endif
  186. TEST(Bits, divTestUint8) {
  187. runDivTests<uint8_t, int8_t, int64_t>();
  188. runDivTests<uint8_t, uint8_t, int64_t>();
  189. runDivTests<uint8_t, int16_t, int64_t>();
  190. runDivTests<uint8_t, uint16_t, int64_t>();
  191. runDivTests<uint8_t, int32_t, int64_t>();
  192. runDivTests<uint8_t, uint32_t, int64_t>();
  193. #if FOLLY_HAVE_INT128_T
  194. runDivTests<uint8_t, int64_t, __int128>();
  195. runDivTests<uint8_t, uint64_t, __int128>();
  196. #endif
  197. }
  198. TEST(Bits, divTestUint16) {
  199. runDivTests<uint16_t, int8_t, int64_t>();
  200. runDivTests<uint16_t, uint8_t, int64_t>();
  201. runDivTests<uint16_t, int16_t, int64_t>();
  202. runDivTests<uint16_t, uint16_t, int64_t>();
  203. runDivTests<uint16_t, int32_t, int64_t>();
  204. runDivTests<uint16_t, uint32_t, int64_t>();
  205. #if FOLLY_HAVE_INT128_T
  206. runDivTests<uint16_t, int64_t, __int128>();
  207. runDivTests<uint16_t, uint64_t, __int128>();
  208. #endif
  209. }
  210. TEST(Bits, divTestUint32) {
  211. runDivTests<uint32_t, int8_t, int64_t>();
  212. runDivTests<uint32_t, uint8_t, int64_t>();
  213. runDivTests<uint32_t, int16_t, int64_t>();
  214. runDivTests<uint32_t, uint16_t, int64_t>();
  215. runDivTests<uint32_t, int32_t, int64_t>();
  216. runDivTests<uint32_t, uint32_t, int64_t>();
  217. #if FOLLY_HAVE_INT128_T
  218. runDivTests<uint32_t, int64_t, __int128>();
  219. runDivTests<uint32_t, uint64_t, __int128>();
  220. #endif
  221. }
  222. #if FOLLY_HAVE_INT128_T
  223. TEST(Bits, divTestUint64) {
  224. runDivTests<uint64_t, int8_t, __int128>();
  225. runDivTests<uint64_t, uint8_t, __int128>();
  226. runDivTests<uint64_t, int16_t, __int128>();
  227. runDivTests<uint64_t, uint16_t, __int128>();
  228. runDivTests<uint64_t, int32_t, __int128>();
  229. runDivTests<uint64_t, uint32_t, __int128>();
  230. runDivTests<uint64_t, int64_t, __int128>();
  231. runDivTests<uint64_t, uint64_t, __int128>();
  232. }
  233. #endif