Przeglądaj źródła

fix: handle division error

chore: update test cases to use newer GMock
Sam Jaffe 2 lat temu
rodzic
commit
40b329330a

+ 2 - 0
bigdecimal.xcodeproj/project.pbxproj

@@ -66,6 +66,7 @@
 		CD47694720AFA150009AA8BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		CD47697520AFA6B2009AA8BB /* biginteger_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = biginteger_test.cpp; sourceTree = "<group>"; };
 		CD47697820AFAC9C009AA8BB /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
+		CD4881C229BE3752008610D5 /* xcode_gtest_helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xcode_gtest_helper.h; sourceTree = "<group>"; };
 		CD5FB2801F06EF7D005A0D61 /* biginteger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = biginteger.cpp; sourceTree = "<group>"; };
 		CD8176CC25C5A4100043E7E7 /* include */ = {isa = PBXFileReference; lastKnownFileType = folder; path = include; sourceTree = "<group>"; };
 		CD8176D325C5A6B50043E7E7 /* bignum_helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bignum_helper.h; sourceTree = "<group>"; };
@@ -160,6 +161,7 @@
 				CDB7F52E20B19E0D0053645C /* bignumber_test_printers.cpp */,
 				CD3B82A31F114E1C0081E9FC /* bignumber_integral_test.cpp */,
 				CD14CA711F0DA9FC0091A168 /* bigdecimal_test.cpp */,
+				CD4881C229BE3752008610D5 /* xcode_gtest_helper.h */,
 			);
 			path = test;
 			sourceTree = "<group>";

+ 11 - 2
src/bigdecimal.cpp

@@ -14,7 +14,8 @@
 using namespace math;
 
 static int32_t add_scale(int32_t scale) {
-  return scale / bigdecimal::SEG_DIGITS + (scale > 0 ? 1 : 0);
+  if (scale > 0) { return (scale - 1) / bigdecimal::SEG_DIGITS + 1; }
+  return scale / bigdecimal::SEG_DIGITS;
 }
 
 static size_t mul_scale(int32_t scale) {
@@ -200,8 +201,16 @@ bigdecimal & math::operator/=(bigdecimal & rhs, bigdecimal const & lhs) {
   } else if (rhs == bigdecimal::ZERO) {
     rhs = bigdecimal::ZERO;
   } else if (!is_one(lhs.data, lhs.scale())) {
-    if (rhs.scale() < new_scale) rhs.rescale(new_scale);
+    constexpr auto SEG_DIGITS = bigdecimal::SEG_DIGITS;
+    if (rhs.scale() < new_scale) { rhs.rescale(new_scale); }
+
     auto cmp = detail::compare(rhs.data, lhs.data);
+    for (int steps = 0;
+         cmp < 0 && new_scale > 0 && steps <= new_scale / SEG_DIGITS; ++steps) {
+      rhs.rescale(rhs.scale() + SEG_DIGITS);
+      cmp = detail::compare(rhs.data, lhs.data);
+    }
+
     if (cmp < 0) {
       rhs = bigdecimal::ZERO;
     } else if (cmp == 0) {

+ 12 - 4
test/bigdecimal_test.cpp

@@ -6,6 +6,7 @@
 //
 
 #include "bignumber_test_printers.h"
+#include "xcode_gtest_helper.h"
 
 TEST(BigDecimalTest, ConstructIntegerAsDecimal) {
   EXPECT_THAT(math::bigdecimal(1000, 2).to_string(), "1000.00");
@@ -117,6 +118,13 @@ TEST_P(DivisionScaleTest, ScaleIsDifferenceOfNumAndDenomScales) {
   EXPECT_THAT(out.to_string(), tup.expected);
 }
 
+TEST(MultiplicationTest, ProperlyScales) {
+  math::bigdecimal num("6565.000000");
+  math::bigdecimal den("185749.82");
+
+  EXPECT_THAT(num / den, math::bigdecimal("0.035343237", 4));
+}
+
 class EqTest : public testing::TestWithParam<BigDecPair> {};
 
 TEST_P(EqTest, DecimalsAreEqualEvenIfScalesAreNot) {
@@ -133,7 +141,7 @@ TEST_P(DecimalLtTest, IsLessThanEvenWithDifferentScales) {
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     BigDecimal, MultiplicationScaleTest,
     testing::Values(ArithTuple{{1, 1}, {1, 0}, "1.0"},
                     ArithTuple{{1, 0}, {1, 1}, "1.0"},
@@ -151,7 +159,7 @@ INSTANTIATE_TEST_CASE_P(
                     ArithTuple{{100, -2}, {1000000000, -9}, "100000000000"},
                     ArithTuple{{10000, -4}, {100000, -5}, "1000000000"}));
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     BigDecimal, DivisionScaleTest,
     testing::Values(
         ArithTuple{{1, 1}, {1, 0}, "1.0"}, ArithTuple{{1, 0}, {1, 1}, "0"},
@@ -164,13 +172,13 @@ INSTANTIATE_TEST_CASE_P(
         ArithTuple{{10000, -4}, {100000, -5}, "0.1"},
         ArithTuple{{"11.0"}, {"1.10"}, "10"}));
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     BigDecimal, EqTest,
     testing::Values(BigDecPair{{0}, {0, 4}}, BigDecPair{{100}, {100, -2}},
                     BigDecPair{{1000000000, -4}, {1000000000, -9}},
                     BigDecPair{{"0.1", 1}, {"0.10", 2}}));
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     BigDecimal, DecimalLtTest,
     testing::Values(BigDecPair{{0, 0}, {1, 4}}, BigDecPair{{0, 4}, {1, 0}},
                     BigDecPair{{0, 4}, {1, 4}}, BigDecPair{{-1, 4}, {1, 4}},

+ 16 - 18
test/biginteger_test.cpp

@@ -6,6 +6,7 @@
 //
 
 #include "bignumber_test_printers.h"
+#include "xcode_gtest_helper.h"
 
 TEST(BigIntegerTest, ModuloZeroThrows) {
   math::biginteger bi{1000};
@@ -54,23 +55,20 @@ TEST_P(LtTest, IsLessThan) {
   EXPECT_THAT(std::get<0>(pair), testing::Lt(std::get<1>(pair)));
 }
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-INSTANTIATE_TEST_CASE_P(BigInteger, LtTest,
-                        testing::Values(BigIntPair{-1, 1}, BigIntPair{0, 1},
-                                        BigIntPair{-2, -1},
-                                        BigIntPair{1000000000, 1000000001},
-                                        BigIntPair{-1000000001, -1000000000}));
+INSTANTIATE_TEST_SUITE_P(BigInteger, LtTest,
+                         testing::Values(BigIntPair{-1, 1}, BigIntPair{0, 1},
+                                         BigIntPair{-2, -1},
+                                         BigIntPair{1000000000, 1000000001},
+                                         BigIntPair{-1000000001, -1000000000}));
 
-INSTANTIATE_TEST_CASE_P(ZeroModAny, BigIntModuloTest,
-                        testing::Combine(testing::Values(0),
-                                         testing::Values(1, 2, 10, 100, -4,
-                                                         1000000000,
-                                                         -1000000000)));
+INSTANTIATE_TEST_SUITE_P(ZeroModAny, BigIntModuloTest,
+                         testing::Combine(testing::Values(0),
+                                          testing::Values(1, 2, 10, 100, -4,
+                                                          1000000000,
+                                                          -1000000000)));
 
-INSTANTIATE_TEST_CASE_P(AnyModOne, BigIntModuloTest,
-                        testing::Combine(testing::Values(1, 2, 10, 100, -4,
-                                                         1000000000,
-                                                         -1000000000),
-                                         testing::Values(1)));
-#pragma clang diagnostic pop
+INSTANTIATE_TEST_SUITE_P(AnyModOne, BigIntModuloTest,
+                         testing::Combine(testing::Values(1, 2, 10, 100, -4,
+                                                          1000000000,
+                                                          -1000000000),
+                                          testing::Values(1)));

+ 2 - 1
test/bignumber_integral_test.cpp

@@ -6,6 +6,7 @@
 //
 
 #include "bignumber_test_printers.h"
+#include "xcode_gtest_helper.h"
 
 template <typename T> class BigIntLikeTest : public testing::Test {
 public:
@@ -14,7 +15,7 @@ public:
 #define BigNumber decltype(this->typeget_)
 
 typedef testing::Types<math::biginteger, math::bigdecimal> IntLikeBigNumbers;
-TYPED_TEST_CASE(BigIntLikeTest, IntLikeBigNumbers);
+TYPED_TEST_SUITE(BigIntLikeTest, IntLikeBigNumbers);
 
 TYPED_TEST(BigIntLikeTest, DefaultConstructorCreatesZero) {
   EXPECT_THAT(BigNumber(), 0);

+ 0 - 5
test/bignumber_test_printers.h

@@ -14,11 +14,6 @@
 #include <string>
 #include <tuple>
 
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
-#include <gmock/gmock.h>
-#pragma clang diagnostic pop
-
 struct ArithTuple {
   math::bigdecimal lhs, rhs;
   std::string expected;

+ 38 - 0
test/xcode_gtest_helper.h

@@ -0,0 +1,38 @@
+//
+//  xcode_gtest_helper.h
+//
+//  Created by Sam Jaffe on 11/25/20.
+//  Copyright © 2020 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#if defined(__APPLE__)
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
+#pragma clang diagnostic ignored "-Wcomma"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#pragma clang diagnostic pop
+
+#if defined(TARGET_OS_OSX)
+// This is a hack to allow XCode to properly display failures when running
+// unit tests.
+#undef EXPECT_THAT
+#define EXPECT_THAT ASSERT_THAT
+#undef EXPECT_THROW
+#define EXPECT_THROW ASSERT_THROW
+#undef EXPECT_ANY_THROW
+#define EXPECT_ANY_THROW ASSERT_ANY_THROW
+#undef EXPECT_NO_THROW
+#define EXPECT_NO_THROW ASSERT_NO_THROW
+#undef EXPECT_TRUE
+#define EXPECT_TRUE ASSERT_TRUE
+#undef EXPECT_FALSE
+#define EXPECT_FALSE ASSERT_FALSE
+
+#endif
+#endif