bigdecimal.t.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. //
  2. // bigdecimal.t.h
  3. // bigdecimal
  4. //
  5. // Created by Sam Jaffe on 7/5/17.
  6. //
  7. #pragma once
  8. #include "bigdecimal.h"
  9. #include <cxxtest/TestSuite.h>
  10. class bigdecimal_TestSuite : public CxxTest::TestSuite {
  11. public:
  12. // void testConstructFromStringIsSameValueAsFromInt() {
  13. // using bi = math::bigdecimal;
  14. // TS_ASSERT_EQUALS(bi("1000000"), bi(1000000));
  15. // }
  16. //
  17. void testConstructIntegerAsDecimal() {
  18. using bd = math::bigdecimal;
  19. TS_ASSERT_EQUALS(bd("1000.00").to_string(), "1000.00");
  20. }
  21. void testConstructDecimal() {
  22. using bd = math::bigdecimal;
  23. TS_ASSERT_EQUALS(bd("1000.10").to_string(), "1000.10");
  24. TS_ASSERT_EQUALS(bd("1000.01").to_string(), "1000.01");
  25. }
  26. void testRescaleHigherAddsDigits() {
  27. math::bigdecimal dec(100);
  28. TS_ASSERT_EQUALS(dec.scale(), 0);
  29. dec.rescale(2);
  30. TS_ASSERT_EQUALS(dec.to_string(), "100.00");
  31. }
  32. void testRescaleLowerCanBeLossy() {
  33. math::bigdecimal dec("100.10");
  34. TS_ASSERT_EQUALS(dec.scale(), 2);
  35. dec.rescale(0);
  36. dec.rescale(2);
  37. TS_ASSERT_EQUALS(dec.to_string(), "100.00");
  38. }
  39. void testNegativeScaleLosesLowerDigits() {
  40. math::bigdecimal dec("123", -2);
  41. TS_ASSERT_EQUALS(dec.to_string(), "100");
  42. }
  43. void testConstructWithScaleEqualsWithout() {
  44. math::bigdecimal scl(100, -2);
  45. TS_ASSERT_EQUALS(scl.to_string(), "100");
  46. }
  47. void testScaleBelowNegSegDoesntLoseAnything() {
  48. TS_ASSERT_EQUALS(math::bigdecimal("1000000000", -9).to_string(),
  49. "1000000000");
  50. }
  51. void testAddTwoDecimalsSameScale() {
  52. using bd = math::bigdecimal;
  53. bd a("1000.10");
  54. bd b("1000.01");
  55. TS_ASSERT_EQUALS(a.scale(), b.scale());
  56. TS_ASSERT_EQUALS((a+b).to_string(), "2000.11");
  57. }
  58. void testAddTwoDecimalsDifferentScalesUsesHigherScale() {
  59. using bd = math::bigdecimal;
  60. bd a("1000.10");
  61. bd b("1000");
  62. TS_ASSERT(a.scale() > b.scale());
  63. TS_ASSERT_EQUALS((a+b).to_string(), "2000.10");
  64. }
  65. void testAddNumberWithInversePreservesScale() {
  66. math::bigdecimal a("1.001");
  67. TS_ASSERT_EQUALS((a+(-a)).to_string(), "0.000");
  68. }
  69. void testSubtractTwoDecimalsDifferentScalesUsesHigherScale() {
  70. using bd = math::bigdecimal;
  71. bd a("900.10");
  72. bd b("1000");
  73. TS_ASSERT(a.scale() > b.scale());
  74. TS_ASSERT_EQUALS((a-b).to_string(), "-99.90");
  75. TS_ASSERT_EQUALS((b-a).to_string(), "99.90");
  76. }
  77. void testMultiplicationIncreasesScale() {
  78. math::bigdecimal bd("1.1");
  79. auto out = bd * bd;
  80. TS_ASSERT_EQUALS(out.scale(), bd.scale() + bd.scale());
  81. TS_ASSERT_EQUALS(out.to_string(), "1.21");
  82. }
  83. void testMultiplicationNegativeScaleCountersPositiveScale() {
  84. math::bigdecimal a("0.01");
  85. math::bigdecimal b("100", -2);
  86. TS_ASSERT_EQUALS((a*b).to_string(), "1");
  87. }
  88. void testMultiplicationCreateNewOffsetCell() {
  89. math::bigdecimal C(1, 5);
  90. TS_ASSERT_EQUALS((C*C).to_string(), "1.0000000000");
  91. }
  92. void testMultiplicationNegativeToPositiveScale() {
  93. math::bigdecimal C(1, 5);
  94. math::bigdecimal D(100, -2);
  95. TS_ASSERT_EQUALS((D*C).to_string(), "100.000");
  96. }
  97. void testMultiplicationFromDroppedToNonDropScale() {
  98. math::bigdecimal C(1, 5);
  99. math::bigdecimal E(1000000000, -9);
  100. TS_ASSERT_EQUALS((E*C).to_string(), "1000000000");
  101. }
  102. void testMultiplicationFromDroppedToLowerScale() {
  103. math::bigdecimal D(100, -2);
  104. math::bigdecimal E(1000000000, -9);
  105. TS_ASSERT_EQUALS((E*D).to_string(), "100000000000");
  106. }
  107. void testMultiplicationFromNonDropToDroppedScale() {
  108. math::bigdecimal F(10000, -4);
  109. math::bigdecimal G(100000, -5);
  110. TS_ASSERT_EQUALS((G*F).to_string(), "1000000000");
  111. }
  112. math::bigdecimal __create(int32_t scale) {
  113. if (scale >= 0) return { "1", scale };
  114. std::vector<char> data(size_t(std::abs(scale))+3, 0);
  115. data[0] = '1';
  116. sprintf(data.data()+1, "%0.*d", -scale, 0);
  117. return { data.data(), scale };
  118. }
  119. std::string __createExpect(int32_t scale1, int32_t scale2) {
  120. int32_t decimals{0}, magnitude{std::min(scale1, scale2)};
  121. if (scale1 < 0 == scale2 < 0) {
  122. decimals = scale1 + scale2;
  123. } else if (scale1 > 0 && scale1 > -scale2) {
  124. decimals = scale1 + scale2;
  125. } else if (scale2 > 0 && scale2 > -scale1) {
  126. decimals = scale1 + scale2;
  127. } else {
  128. decimals = std::min(scale1, scale2);
  129. }
  130. if (decimals < 0) { magnitude = decimals; }
  131. std::vector<char> data(size_t(std::abs(decimals) + std::abs(magnitude))+4, 0);
  132. char * ptr = data.data();
  133. *ptr++ = '1';
  134. if (magnitude < 0) {
  135. ptr += sprintf(ptr, "%0.*d", -magnitude, 0);
  136. }
  137. if (decimals > 0) {
  138. sprintf(ptr, ".%0.*d", decimals, 0);
  139. }
  140. return data.data();
  141. }
  142. void __testMultiplyScales(int32_t scale1, int32_t scale2) {
  143. math::bigdecimal A(__create(scale1));
  144. math::bigdecimal B(__create(scale2));
  145. // This is wrong
  146. std::string expected(__createExpect(scale1, scale2));
  147. TS_ASSERT_EQUALS((A*B).to_string(), expected);
  148. TS_ASSERT_EQUALS((B*A).to_string(), expected);
  149. }
  150. void testMultiplicationBrutePermutations() {
  151. for (int32_t i = -20; i <= +20; ++i) {
  152. for (int32_t j = i; j <= +20; ++j) {
  153. __testMultiplyScales(i, j);
  154. }
  155. }
  156. }
  157. void testDivideHigherScaleByLowerScale() {
  158. math::bigdecimal a("1", 2);
  159. math::bigdecimal b("1", 1);
  160. TS_ASSERT_EQUALS((a/b).to_string(), "1.0");
  161. }
  162. void testDivideLowerScaleByHigherScale() {
  163. math::bigdecimal a("10", 1);
  164. math::bigdecimal b("1", 2);
  165. TS_ASSERT_EQUALS((a/b).to_string(), "10");
  166. }
  167. };