yql_decimal_ut.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #include <yql/essentials/public/decimal/yql_decimal.h>
  2. #include <yql/essentials/public/decimal/yql_decimal_serialize.h>
  3. #include <library/cpp/testing/unittest/registar.h>
  4. namespace NYql {
  5. namespace NDecimal {
  6. Y_UNIT_TEST_SUITE(TYqlDecimalTest) {
  7. void SimplePositiveTest(TInt128 v, ui8 precision, ui8 scale, const TString& expected) {
  8. TString result = ToString(v, precision, scale);
  9. UNIT_ASSERT_VALUES_EQUAL(result, expected);
  10. TInt128 parsed = FromString(result, precision, scale);
  11. UNIT_ASSERT(parsed == v);
  12. }
  13. void SimpleNegativeFormatTest(TInt128 v, ui8 precision, ui8 scale) {
  14. TString result = ToString(v, precision, scale);
  15. UNIT_ASSERT_VALUES_EQUAL(result, "");
  16. }
  17. void SimpleSerializeAndDeserialize(TInt128 v, size_t expectedSize) {
  18. char buff[sizeof(TInt128)];
  19. const auto s = Serialize(v, buff);
  20. UNIT_ASSERT_VALUES_EQUAL(s, expectedSize);
  21. const auto& des = Deserialize(buff, expectedSize);
  22. UNIT_ASSERT_VALUES_EQUAL(des.second, expectedSize);
  23. UNIT_ASSERT(des.first == v);
  24. const auto& e = Deserialize(buff, expectedSize - 1);
  25. UNIT_ASSERT(e.first == Err());
  26. }
  27. template<ui8 Precision, ui8 Scale>
  28. void CheckMulAndRescale(const TStringBuf& lhs, const TStringBuf& rhs, const TStringBuf& expected) {
  29. const auto l = FromString(lhs, Precision, Scale);
  30. const auto r = FromString(rhs, Precision, Scale);
  31. const auto m = MulAndDivNormalDivider(l, r, GetDivider<Scale>());
  32. const auto result = ToString(m, Precision, Scale);
  33. UNIT_ASSERT_VALUES_EQUAL(result, expected);
  34. }
  35. template<ui8 Precision, ui8 Scale>
  36. void CheckDivAndRescale(const TStringBuf& lhs, const TStringBuf& rhs, const TStringBuf& expected) {
  37. const auto l = FromString(lhs, Precision, Scale);
  38. const auto r = FromString(rhs, Precision, Scale);
  39. const auto m = MulAndDivNormalMultiplier(l, GetDivider<Scale>(), r);
  40. const auto result = ToString(m, Precision, Scale);
  41. UNIT_ASSERT_VALUES_EQUAL(result, expected);
  42. }
  43. template<ui8 Precision, ui8 Scale = 0>
  44. void CheckMul(const TStringBuf& lhs, const TStringBuf& rhs, const TStringBuf& expected) {
  45. const auto l = FromString(lhs, Precision, Scale);
  46. const auto r = FromString(rhs, Precision, Scale);
  47. const auto m = Mul(l, r);
  48. const auto result = ToString(m, Precision, Scale);
  49. UNIT_ASSERT_VALUES_EQUAL(result, expected);
  50. }
  51. Y_UNIT_TEST(TestZeroFormat) {
  52. UNIT_ASSERT_VALUES_EQUAL(ToString(0, 1, 0), "0");
  53. UNIT_ASSERT_VALUES_EQUAL(ToString(0, 15, 6), "0");
  54. UNIT_ASSERT_VALUES_EQUAL(ToString(0, 15, 0), "0");
  55. }
  56. Y_UNIT_TEST(TestZeroScale) {
  57. SimplePositiveTest(1, 5, 0, "1");
  58. SimplePositiveTest(10, 5, 0, "10");
  59. SimplePositiveTest(100, 5, 0, "100");
  60. SimplePositiveTest(1000, 5, 0, "1000");
  61. SimplePositiveTest(10000, 5, 0, "10000");
  62. SimpleNegativeFormatTest(100000, 5, 0);
  63. SimpleNegativeFormatTest(1000000, 5, 0);
  64. // negative numbers
  65. SimplePositiveTest(-1, 5, 0, "-1");
  66. SimplePositiveTest(-10, 5, 0, "-10");
  67. SimplePositiveTest(-100, 5, 0, "-100");
  68. SimplePositiveTest(-1000, 5, 0, "-1000");
  69. SimplePositiveTest(-10000, 5, 0, "-10000");
  70. SimpleNegativeFormatTest(-100000, 5, 0);
  71. }
  72. Y_UNIT_TEST(TestFormats) {
  73. // we have no trailing zeros
  74. SimplePositiveTest(1, 15, 6, "0.000001");
  75. SimplePositiveTest(10, 15, 6, "0.00001");
  76. SimplePositiveTest(100, 15, 6, "0.0001");
  77. SimplePositiveTest(1000, 15, 6, "0.001");
  78. SimplePositiveTest(10000, 15, 6, "0.01");
  79. SimplePositiveTest(100000, 15, 6, "0.1");
  80. SimplePositiveTest(1000000, 15, 6, "1");
  81. SimplePositiveTest(10000000, 15, 6, "10");
  82. SimplePositiveTest(100000000, 15, 6, "100");
  83. SimplePositiveTest(2020000, 15, 6, "2.02");
  84. SimplePositiveTest(3003000, 15, 6, "3.003");
  85. // negative numbers
  86. SimplePositiveTest(-1, 15, 6, "-0.000001");
  87. SimplePositiveTest(-10, 15, 6, "-0.00001");
  88. SimplePositiveTest(-100, 15, 6, "-0.0001");
  89. SimplePositiveTest(-1000, 15, 6, "-0.001");
  90. SimplePositiveTest(-10000, 15, 6, "-0.01");
  91. SimplePositiveTest(-100000, 15, 6, "-0.1");
  92. SimplePositiveTest(-1000000, 15, 6, "-1");
  93. SimplePositiveTest(-10000000, 15, 6, "-10");
  94. SimplePositiveTest(-100000000, 15, 6, "-100");
  95. SimplePositiveTest(-2020000, 15, 6, "-2.02");
  96. SimplePositiveTest(-3003000, 15, 6, "-3.003");
  97. SimplePositiveTest(1, 15, 6, "0.000001");
  98. SimplePositiveTest(12, 15, 6, "0.000012");
  99. SimplePositiveTest(123, 15, 6, "0.000123");
  100. SimplePositiveTest(1234, 15, 6, "0.001234");
  101. SimplePositiveTest(12345, 15, 6, "0.012345");
  102. SimplePositiveTest(123456, 15, 6, "0.123456");
  103. SimplePositiveTest(1234567, 15, 6, "1.234567");
  104. SimplePositiveTest(12345678, 15, 6, "12.345678");
  105. SimplePositiveTest(123456789, 15, 6, "123.456789");
  106. SimplePositiveTest(1234567898, 15, 6, "1234.567898");
  107. SimplePositiveTest(12345678987ll, 15, 6, "12345.678987");
  108. SimplePositiveTest(123456789876ll, 15, 6, "123456.789876");
  109. }
  110. Y_UNIT_TEST(TestHugeNumberFormat) {
  111. TInt128 max120 = Inf() - 1;
  112. const char max120String[] = "99999999999999999999999999999999999"; // 35 digits
  113. static_assert(sizeof(max120String) == 36, "sizeof(max120String) == 36");
  114. SimplePositiveTest(max120, MaxPrecision, 0, max120String);
  115. SimplePositiveTest(max120 + 1, MaxPrecision, 0, "inf");
  116. TInt128 min120 = -Inf() + 1;
  117. const char min120String[] = "-99999999999999999999999999999999999";
  118. static_assert(sizeof(min120String) == 37, "sizeof(min120String) == 37");
  119. SimplePositiveTest(min120, MaxPrecision, 0, min120String);
  120. SimplePositiveTest(min120 - 1, MaxPrecision, 0, "-inf");
  121. // take spot for sign and zero before dot
  122. const char min120StringAfterDot[] = "-0.99999999999999999999999999999999999"; // 35 by nine + leading zero
  123. static_assert(sizeof(min120StringAfterDot) == 39, "sizeof(min120StringAfterDot) == 39");
  124. SimplePositiveTest(min120, MaxPrecision, MaxPrecision, min120StringAfterDot);
  125. SimpleNegativeFormatTest(1, MaxPrecision + 1, MaxPrecision + 1);
  126. SimpleNegativeFormatTest(1, MaxPrecision + 1, 0);
  127. SimpleNegativeFormatTest(1, 2, 3);
  128. }
  129. Y_UNIT_TEST(TestFormStringRoundToEven) {
  130. UNIT_ASSERT(FromString(".51", 1, 0) == 1);
  131. UNIT_ASSERT(FromString("-0.51", 1, 0) == -1);
  132. UNIT_ASSERT(FromString("+00000008.5", 1, 0) == 8);
  133. UNIT_ASSERT(FromString("-8.5000000000000000000000000000000", 1, 0) == -8);
  134. UNIT_ASSERT(FromString("00008.51", 1, 0) == 9);
  135. UNIT_ASSERT(FromString("-8.5000000000000000000000000000001", 1, 0) == -9);
  136. UNIT_ASSERT(FromString("09.499999999999999999999999999999999999999999999999999999999", 1, 0) == 9);
  137. UNIT_ASSERT(FromString("-9.499999999999999999999999999999999999999999999999999999999", 1, 0) == -9);
  138. UNIT_ASSERT(FromString("9.50", 2, 0) == 10);
  139. UNIT_ASSERT(FromString("-9.5", 2, 0) == -10);
  140. UNIT_ASSERT(FromString("+0.9949", 2, 2) == 99);
  141. UNIT_ASSERT(FromString("-0.9949", 2, 2) == -99);
  142. }
  143. Y_UNIT_TEST(TestInfinityValues) {
  144. UNIT_ASSERT(FromString("+1", 1, 1) == Inf());
  145. UNIT_ASSERT(FromString("-1", 1, 1) == -Inf());
  146. UNIT_ASSERT(FromString("10.000", 1, 0) == Inf());
  147. UNIT_ASSERT(FromString("-10.000", 1, 0) == -Inf());
  148. UNIT_ASSERT(FromString("9.500", 1, 0) == Inf());
  149. UNIT_ASSERT(FromString("-9.500", 1, 0) == -Inf());
  150. UNIT_ASSERT(FromString("+0.950", 1, 1) == Inf());
  151. UNIT_ASSERT(FromString("-0.950", 1, 1) == -Inf());
  152. UNIT_ASSERT(FromString("+0.9950", 2, 2) == Inf());
  153. UNIT_ASSERT(FromString("-0.9950", 2, 2) == -Inf());
  154. UNIT_ASSERT(FromString("9999999999999999999999999999999999999.5", 35, 0) == Inf());
  155. UNIT_ASSERT(FromString("-9999999999999999999999999999999999999.5", 35, 0) == -Inf());
  156. }
  157. Y_UNIT_TEST(TestInvalidValues) {
  158. UNIT_ASSERT(IsValid("+999999999999999991234567890.039493804903849038490312345678909999999999999999990"));
  159. UNIT_ASSERT(!IsValid("")); // empty
  160. UNIT_ASSERT(!IsValid("12.2.3")); // double dot
  161. UNIT_ASSERT(!IsValid("+-12")); // extra sign
  162. UNIT_ASSERT(!IsValid("463786378O74674")); // letter inside
  163. UNIT_ASSERT(IsError(FromString("", 35, 15))); // empty
  164. UNIT_ASSERT(IsError(FromString("12.2.3", 35, 15))); // double dot
  165. UNIT_ASSERT(IsError(FromString("+-12", 35, 15))); // extra sign
  166. UNIT_ASSERT(IsError(FromString("463786378O74674", 35, 15))); // letter inside
  167. UNIT_ASSERT(IsError(FromString("+7.039493804E1", 35, 5))); // letter in tail after scale
  168. }
  169. Y_UNIT_TEST(TestFormStringEx) {
  170. UNIT_ASSERT(FromStringEx("NAN", 13, 1) == Nan());
  171. UNIT_ASSERT(FromStringEx("+inf", 11, 7) == Inf());
  172. UNIT_ASSERT(FromStringEx("-inf", 7, 7) == -Inf());
  173. UNIT_ASSERT(FromStringEx("0.1E3", 10, 1) == 1000);
  174. UNIT_ASSERT(FromStringEx("0.51e-3", 10, 3) == 1);
  175. UNIT_ASSERT(FromStringEx("1E30", 10, 0) == Inf());
  176. UNIT_ASSERT(FromStringEx("1e-30", 10, 0) == 0);
  177. UNIT_ASSERT(FromStringEx("-1E+99", 10, 2) == -Inf());
  178. UNIT_ASSERT(FromStringEx("-1e-99", 10, 2) == 0);
  179. UNIT_ASSERT(FromStringEx("-510e-3", 1, 0) == -1);
  180. UNIT_ASSERT(FromStringEx("+99E3", 5, 0) == 99000);
  181. UNIT_ASSERT(FromStringEx("2.1E-130", 35, 2) == 0);
  182. UNIT_ASSERT(FromStringEx("2.1E0", 35, 2) == 210);
  183. }
  184. Y_UNIT_TEST(TestFormStringExInvalidValues) {
  185. UNIT_ASSERT(IsError(FromStringEx("", 35, 15))); // empty
  186. UNIT_ASSERT(IsError(FromStringEx("12.2.3", 35, 15))); // double dot
  187. UNIT_ASSERT(IsError(FromStringEx("+-12", 35, 15))); // extra sign
  188. UNIT_ASSERT(IsError(FromStringEx("463786378O74674", 35, 15))); // letter inside
  189. UNIT_ASSERT(IsError(FromStringEx("E2", 35, 15))); // empty
  190. UNIT_ASSERT(IsError(FromStringEx("E2E4", 35, 15))); // empty
  191. UNIT_ASSERT(IsError(FromStringEx("NANE5", 35, 15))); // nan with exp
  192. UNIT_ASSERT(IsError(FromStringEx("infE5", 35, 15))); // inf with exp
  193. UNIT_ASSERT(IsError(FromStringEx("-infe-5", 35, 15))); // inf with exp
  194. UNIT_ASSERT(IsError(FromStringEx("2.1E0X", 35, 2))); // not fully parsed exp
  195. UNIT_ASSERT(IsError(FromStringEx("2.1E+-1", 35, 2))); // two signs
  196. UNIT_ASSERT(IsError(FromStringEx("ae30", 10, 0))); // bad mantissa
  197. }
  198. Y_UNIT_TEST(TestSpecialAsString) {
  199. UNIT_ASSERT(IsValid("Nan"));
  200. UNIT_ASSERT(IsValid("INF"));
  201. UNIT_ASSERT(IsValid("-inf"));
  202. UNIT_ASSERT_VALUES_EQUAL(ToString(Nan(), 10, 2), "nan");
  203. UNIT_ASSERT_VALUES_EQUAL(ToString(+Inf(), 10, 2), "inf");
  204. UNIT_ASSERT_VALUES_EQUAL(ToString(-Inf(), 10, 2), "-inf");
  205. UNIT_ASSERT(IsNan(FromString("nan", 10, 2)));
  206. UNIT_ASSERT(IsInf(FromString("+INf", MaxPrecision, 6)));
  207. UNIT_ASSERT(IsInf(FromString("-inF", 4, 2)));
  208. }
  209. Y_UNIT_TEST(TestToStringOfNonNormal) {
  210. // above Inf
  211. for (TInt128 i = Inf() + 2, end = Inf() + 100; i < end; i++) {
  212. UNIT_ASSERT(!IsNormal(i));
  213. UNIT_ASSERT(ToString(i, MaxPrecision, 0) == nullptr);
  214. }
  215. // below -Inf
  216. for (TInt128 i = -Inf() - 2, end = -Inf() - 100; i < end; i--) {
  217. UNIT_ASSERT(!IsNormal(i));
  218. UNIT_ASSERT(ToString(i, MaxPrecision, 0) == nullptr);
  219. }
  220. }
  221. Y_UNIT_TEST(TestSerializeAndDeserialize) {
  222. SimpleSerializeAndDeserialize(-Nan(), 1U);
  223. SimpleSerializeAndDeserialize(-Inf(), 1U);
  224. SimpleSerializeAndDeserialize(-Inf() + 1, 16U);
  225. SimpleSerializeAndDeserialize(-Inf() + 2, 16U);
  226. SimpleSerializeAndDeserialize(-65537, 4U);
  227. SimpleSerializeAndDeserialize(-65536, 3U);
  228. SimpleSerializeAndDeserialize(-257, 3U);
  229. SimpleSerializeAndDeserialize(-256, 2U);
  230. SimpleSerializeAndDeserialize(-3, 2U);
  231. SimpleSerializeAndDeserialize(-2, 2U);
  232. SimpleSerializeAndDeserialize(-1, 1U);
  233. SimpleSerializeAndDeserialize(0, 1U);
  234. SimpleSerializeAndDeserialize(+1, 2U);
  235. SimpleSerializeAndDeserialize(+2, 2U);
  236. SimpleSerializeAndDeserialize(+255, 2U);
  237. SimpleSerializeAndDeserialize(+256, 3U);
  238. SimpleSerializeAndDeserialize(+65535, 3U);
  239. SimpleSerializeAndDeserialize(+65536, 4U);
  240. SimpleSerializeAndDeserialize(+Inf() - 2, 16U);
  241. SimpleSerializeAndDeserialize(+Inf() - 1, 16U);
  242. SimpleSerializeAndDeserialize(+Inf(), 1U);
  243. SimpleSerializeAndDeserialize(+Nan(), 1U);
  244. }
  245. Y_UNIT_TEST(TestMulAndRescale) {
  246. CheckMulAndRescale<35,35>("0.99999999999999999999999999999999999", "-0.99999999999999999999999999999999999", "-0.99999999999999999999999999999999998");
  247. CheckMulAndRescale<35,35>("-0.99999999999999999999999999999999999", "0.33333333333333333333333333333333333", "-0.33333333333333333333333333333333333");
  248. CheckMulAndRescale<35,35>("0.33333333333333333333333333333333333", "0.33333333333333333333333333333333333", "0.11111111111111111111111111111111111");
  249. CheckMulAndRescale<35,35>("0.99999999999999999999999999999999999", "0.000000000000001", "0.000000000000001");
  250. CheckMulAndRescale<35,35>("0.99999999999999999999999999999999999", "0.00000000000000101010101", "0.00000000000000101010101");
  251. CheckMulAndRescale<35,35>("0.12345678901234567890123456789012345", "0.12345678901234567890123456789012345", "0.01524157875323883675049535156256668");
  252. CheckMulAndRescale<35,34>("9.9999999999999999999999999999999999", "-1.9999999999999999999999999999999999", "-inf");
  253. CheckMulAndRescale<35,34>("3.3333333333333333333333333333333333", "3.3333333333333333333333333333333333", "inf");
  254. CheckMulAndRescale<35,34>("3.3333333333333333333333333333333333", "1.3333333333333333333333333333333333", "4.4444444444444444444444444444444443");
  255. CheckMulAndRescale<35,34>("-1.3333333333333333333333333333333333", "1.3333333333333333333333333333333333", "-1.7777777777777777777777777777777777");
  256. CheckMulAndRescale<35,34>("-7", "0", "0");
  257. CheckMulAndRescale<35,34>("inf", "nan", "nan");
  258. CheckMulAndRescale<35,34>("inf", "0", "nan");
  259. CheckMulAndRescale<35,34>("-inf", "-inf", "inf");
  260. }
  261. Y_UNIT_TEST(TestDivAndRescale) {
  262. CheckDivAndRescale<35,35>("-0.99999999999999999999999999999999999", "0.33333333333333333333333333333333333", "-inf");
  263. CheckDivAndRescale<35,35>("0.33333333333333333333333333333333333", "-0.33333333333333333333333333333333333", "-inf");
  264. CheckDivAndRescale<35,35>("0.12345678901234567890123456789012345", "0.12345678901234567890123456789012345", "inf");
  265. CheckDivAndRescale<35,34>("9.9999999999999999999999999999999999", "-1.9999999999999999999999999999999999", "-5.0000000000000000000000000000000002");
  266. CheckDivAndRescale<35,34>("3.3333333333333333333333333333333333", "3.3333333333333333333333333333333333", "1");
  267. CheckDivAndRescale<35,34>("3.3333333333333333333333333333333333", "1.3333333333333333333333333333333333", "2.5");
  268. CheckDivAndRescale<35,34>("-1.7777777777777777777777777777777777", "1.3333333333333333333333333333333333", "-1.3333333333333333333333333333333333");
  269. CheckDivAndRescale<35,34>("-7", "0", "-inf");
  270. CheckDivAndRescale<35,34>("inf", "0", "inf");
  271. CheckDivAndRescale<35,34>("inf", "0", "inf");
  272. CheckDivAndRescale<35,34>("-inf", "inf", "nan");
  273. }
  274. Y_UNIT_TEST(TestWideMul) {
  275. CheckMul<35>("999999999999999", "99999999999999999999", "99999999999999899999000000000000001");
  276. CheckMul<35>("9999999999999999", "99999999999999999999", "inf");
  277. CheckMul<35>("-99999999999999999999999999999999999", "10000000000000000000000000000000000", "-inf");
  278. CheckMul<35>("-99999999999999999999999999999999999", "-1", "99999999999999999999999999999999999");
  279. CheckMul<35>("-99999999999999999999999999999999999", "-2", "inf");
  280. CheckMul<35>("nan", "0", "nan");
  281. CheckMul<35>("inf", "-inf", "-inf");
  282. CheckMul<35>("inf", "nan", "nan");
  283. }
  284. }
  285. }
  286. }