From 7330c2c8c20bc29967768ffadac003f4a3b345bb Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 14 Jan 2015 18:23:13 +0000 Subject: [PATCH] math: move naive bigint multiplication to a static method and add unit tests. --- src/lol/math/bigint.h | 69 +++++++++++++++++++++++-------------------- src/t/math/bigint.cpp | 17 +++++++++++ 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/lol/math/bigint.h b/src/lol/math/bigint.h index 8866bb81..a512d222 100644 --- a/src/lol/math/bigint.h +++ b/src/lol/math/bigint.h @@ -41,8 +41,8 @@ namespace lol template class bigint { - int const bits_per_digit = sizeof(T) * 8 - 1; - T const digit_mask = ~((T)1 << bits_per_digit); + static int const bits_per_digit = sizeof(T) * 8 - 1; + static T const digit_mask = ~((T)1 << bits_per_digit); public: inline bigint() @@ -123,6 +123,7 @@ public: { for (unsigned int i = 0; i < N; ++i) m_digits[i] &= x.m_digits[i]; + return *this; } inline bigint operator &(bigint const &x) const @@ -137,6 +138,7 @@ public: { for (unsigned int i = 0; i < N; ++i) m_digits[i] |= x.m_digits[i]; + return *this; } inline bigint operator |(bigint const &x) const @@ -151,6 +153,7 @@ public: { for (unsigned int i = 0; i < N; ++i) m_digits[i] ^= x.m_digits[i]; + return *this; } inline bigint operator ^(bigint const &x) const @@ -234,36 +237,7 @@ public: template bigint operator *(bigint const &x) const { - /* FIXME: other digit sizes are not supported */ - static_assert(sizeof(T) == sizeof(uint32_t), "ensure T is uint32_t"); - - if (x.is_negative()) - return -(*this * -x); - if (is_negative()) - return -(-*this * x); - - bigint ret(0); - for (unsigned int i = 0; i < N; ++i) - { - T carry(0); - for (unsigned int j = 0; j < M; ++j) - { - uint64_t digit = ret.m_digits[i + j] - + (uint64_t)m_digits[i] * x.m_digits[j] - + carry; - ret.m_digits[i + j] = (T)digit & digit_mask; - carry = (digit >> bits_per_digit) & digit_mask; - } - - for (unsigned int j = M; i + j < M + N && carry != 0; ++i) - { - T digit = ret.m_digits[i + j] + carry; - ret.m_digits[i + j] = (T)digit & digit_mask; - carry = (digit & ~digit_mask) ? T(1) : T(0); - } - } - - return ret; + return mul_naive(*this, x); } /* @@ -356,6 +330,37 @@ private: return ret; } + template + static inline bigint mul_naive(bigint const &a, + bigint const &b) + { + /* FIXME: other digit sizes are not supported */ + static_assert(sizeof(T) == sizeof(uint32_t), "ensure T is uint32_t"); + + bigint ret(0); + for (unsigned int i = 0; i < N; ++i) + { + T carry(0); + for (unsigned int j = 0; j < M; ++j) + { + uint64_t digit = ret.m_digits[i + j] + + (uint64_t)a.m_digits[i] * b.m_digits[j] + + carry; + ret.m_digits[i + j] = (T)digit & a.digit_mask; + carry = (digit >> a.bits_per_digit) & a.digit_mask; + } + + for (unsigned int j = M; i + j < M + N && carry != 0; ++i) + { + T digit = ret.m_digits[i + j] + carry; + ret.m_digits[i + j] = (T)digit & a.digit_mask; + carry = (digit & ~digit_mask) ? T(1) : T(0); + } + } + + return ret; + } + T m_digits[N]; }; diff --git a/src/t/math/bigint.cpp b/src/t/math/bigint.cpp index 94651b92..cf6590dc 100644 --- a/src/t/math/bigint.cpp +++ b/src/t/math/bigint.cpp @@ -219,6 +219,23 @@ lolunit_declare_fixture(bigint_test) lolunit_assert(e >= d); lolunit_assert(e >= e); } + + lolunit_declare_test(multiply) + { + bigint<> a(-10), b(0), c(10); + + lolunit_assert_equal((int32_t)(a * a), 100); + lolunit_assert_equal((int32_t)(a * b), 0); + lolunit_assert_equal((int32_t)(a * c), -100); + + lolunit_assert_equal((int32_t)(b * a), 0); + lolunit_assert_equal((int32_t)(b * b), 0); + lolunit_assert_equal((int32_t)(b * c), 0); + + lolunit_assert_equal((int32_t)(c * a), -100); + lolunit_assert_equal((int32_t)(c * b), 0); + lolunit_assert_equal((int32_t)(c * c), 100); + } }; } /* namespace lol */