Parcourir la source

math: move naive bigint multiplication to a static method and add unit tests.

undefined
Sam Hocevar il y a 10 ans
Parent
révision
7330c2c8c2
2 fichiers modifiés avec 54 ajouts et 32 suppressions
  1. +37
    -32
      src/lol/math/bigint.h
  2. +17
    -0
      src/t/math/bigint.cpp

+ 37
- 32
src/lol/math/bigint.h Voir le fichier

@@ -41,8 +41,8 @@ namespace lol
template<unsigned int N = 16, typename T = uint32_t>
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<N,T> operator &(bigint<N,T> 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<N,T> operator |(bigint<N,T> 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<N,T> operator ^(bigint<N,T> const &x) const
@@ -234,36 +237,7 @@ public:
template<unsigned int M>
bigint<N + M, T> operator *(bigint<M,T> 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<N + M> 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<unsigned int M>
static inline bigint<N + M, T> mul_naive(bigint<N,T> const &a,
bigint<M,T> const &b)
{
/* FIXME: other digit sizes are not supported */
static_assert(sizeof(T) == sizeof(uint32_t), "ensure T is uint32_t");

bigint<N + M> 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];
};



+ 17
- 0
src/t/math/bigint.cpp Voir le fichier

@@ -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 */


Chargement…
Annuler
Enregistrer