Merge "Expand big decimal with arithmetic operators" from Piotr

"
This miniseries expands big_decimal interface with convenience operators
(-=, +, -), provides test cases for it and makes one of the constructors
explicit.

Tests: unit(dev)
"

* 'expand_big_decimal_interface' of https://github.com/psarna/scylla:
  utils: make string-based big decimal constructor explicit
  tests: add more operators to big decimal tests
  utils: add operators to big_decimal
This commit is contained in:
Avi Kivity
2019-07-04 12:59:05 +03:00
3 changed files with 87 additions and 5 deletions

View File

@@ -35,13 +35,30 @@ void test_div(const char *r_cstr, const int64_t q, const char *expected_cstr) {
BOOST_REQUIRE_EQUAL(res.scale(), expected.scale());
}
void test_assignadd(const char *x_cstr, const char *y_cstr, const char *expected_cstr) {
template<typename Op>
void test_op(const char* x_cstr, const char* y_cstr, const char* expected_cstr, Op&& op) {
big_decimal x{x_cstr};
big_decimal y{y_cstr};
big_decimal expected{expected_cstr};
x += y;
BOOST_REQUIRE_EQUAL(x.unscaled_value(), expected.unscaled_value());
BOOST_REQUIRE_EQUAL(x.scale(), expected.scale());
auto ret = op(x, y);
BOOST_REQUIRE_EQUAL(ret.unscaled_value(), expected.unscaled_value());
BOOST_REQUIRE_EQUAL(ret.scale(), expected.scale());
}
void test_assignadd(const char *x_cstr, const char *y_cstr, const char *expected_cstr) {
return test_op(x_cstr, y_cstr, expected_cstr, [](big_decimal& d1, big_decimal& d2) { return d1 += d2; });
}
void test_add(const char *x_cstr, const char *y_cstr, const char *expected_cstr) {
return test_op(x_cstr, y_cstr, expected_cstr, [](big_decimal& d1, big_decimal& d2) { return d1 + d2; });
}
void test_assignsub(const char *x_cstr, const char *y_cstr, const char *expected_cstr) {
return test_op(x_cstr, y_cstr, expected_cstr, [](big_decimal& d1, big_decimal& d2) { return d1 -= d2; });
}
void test_sub(const char *x_cstr, const char *y_cstr, const char *expected_cstr) {
return test_op(x_cstr, y_cstr, expected_cstr, [](big_decimal& d1, big_decimal& d2) { return d1 - d2; });
}
} /* anonymous namespoce */
@@ -128,3 +145,39 @@ BOOST_AUTO_TEST_CASE(test_big_decimal_assignadd) {
test_assignadd("1.0", "1.000", "2.000");
test_assignadd("-1.0", "-1.000", "-2.000");
}
BOOST_AUTO_TEST_CASE(test_big_decimal_add) {
test_add("1", "4", "5");
test_add("1.00", "4.00", "5.00");
test_add("1.000", "4.000", "5.000");
test_add("1", "-1", "0");
test_add("1.00", "-1.00", "0.00");
test_add("1.000", "-1.000", "0.000");
test_add("0.0", "0.000", "0.000");
test_add("1.0", "1.000", "2.000");
test_add("-1.0", "-1.000", "-2.000");
}
BOOST_AUTO_TEST_CASE(test_big_decimal_assignsub) {
test_assignsub("1", "4", "-3");
test_assignsub("1.00", "4.00", "-3.00");
test_assignsub("1.000", "4.000", "-3.000");
test_assignsub("1", "-1", "2");
test_assignsub("1.00", "-1.00", "2.00");
test_assignsub("1.000", "-1.000", "2.000");
test_assignsub("0.0", "0.000", "0.000");
test_assignsub("1.0", "1.000", "0.000");
test_assignsub("-1.0", "1.000", "-2.000");
}
BOOST_AUTO_TEST_CASE(test_big_decimal_sub) {
test_sub("1", "4", "-3");
test_sub("1.00", "4.00", "-3.00");
test_sub("1.000", "4.000", "-3.000");
test_sub("1", "-1", "2");
test_sub("1.00", "-1.00", "2.00");
test_sub("1.000", "-1.000", "2.000");
test_sub("0.0", "0.000", "0.000");
test_sub("1.0", "1.000", "0.000");
test_sub("-1.0", "1.000", "-2.000");
}

View File

@@ -112,6 +112,32 @@ big_decimal& big_decimal::operator+=(const big_decimal& other)
return *this;
}
big_decimal& big_decimal::operator-=(const big_decimal& other) {
if (_scale == other._scale) {
_unscaled_value -= other._unscaled_value;
} else {
boost::multiprecision::cpp_int rescale(10);
auto max_scale = std::max(_scale, other._scale);
boost::multiprecision::cpp_int u = _unscaled_value * boost::multiprecision::pow(rescale, max_scale - _scale);
boost::multiprecision::cpp_int v = other._unscaled_value * boost::multiprecision::pow(rescale, max_scale - other._scale);
_unscaled_value = u - v;
_scale = max_scale;
}
return *this;
}
big_decimal big_decimal::operator+(const big_decimal& other) const {
big_decimal ret(*this);
ret += other;
return ret;
}
big_decimal big_decimal::operator-(const big_decimal& other) const {
big_decimal ret(*this);
ret -= other;
return ret;
}
big_decimal big_decimal::div(const ::uint64_t y, const rounding_mode mode) const
{
if (mode != rounding_mode::HALF_EVEN) {

View File

@@ -34,7 +34,7 @@ public:
HALF_EVEN,
};
big_decimal(sstring_view text);
explicit big_decimal(sstring_view text);
big_decimal() : big_decimal(0, 0) {}
big_decimal(int32_t scale, boost::multiprecision::cpp_int unscaled_value)
: _scale(scale), _unscaled_value(unscaled_value)
@@ -48,6 +48,9 @@ public:
int compare(const big_decimal& other) const;
big_decimal& operator+=(const big_decimal& other);
big_decimal& operator-=(const big_decimal& other);
big_decimal operator+(const big_decimal& other) const;
big_decimal operator-(const big_decimal& other) const;
big_decimal div(const ::uint64_t y, const rounding_mode mode) const;
friend bool operator<(const big_decimal& x, const big_decimal& y) { return x.compare(y) < 0; }
friend bool operator<=(const big_decimal& x, const big_decimal& y) { return x.compare(y) <= 0; }