Browse Source

math: bigint multiplication (the naïve O(n²) algorithm for now).

undefined
Sam Hocevar 10 years ago
parent
commit
9b857804aa
2 changed files with 78 additions and 3 deletions
  1. +6
    -2
      demos/test/sandbox/sample.cpp
  2. +72
    -1
      src/lol/math/bigint.h

+ 6
- 2
demos/test/sandbox/sample.cpp View File

@@ -23,10 +23,14 @@ int main()
bigint<16> i;
bigint<16> x(2), y(12);
auto z = x + y;
printf("%d\n", (int)z);
printf("0x%x\n", (int)z);
z.print();

bigint<0> lol;
auto w = z + lol;
printf("%d\n", (int)w);
printf("0x%x\n", (int)w);

bigint<2> f(0x10101010), g(0x20202020);
(f * f * f * g - g).print();
}


+ 72
- 1
src/lol/math/bigint.h View File

@@ -207,6 +207,7 @@ public:
/*
* bigint subtraction: a combination of addition and unary minus;
* we add the result of flipping digits and adding one.
* FIXME: this could be factored with operator+().
*/
template<unsigned int M>
bigint<(N > M) ? N : M, T> operator -(bigint<M,T> const &x) const
@@ -226,6 +227,45 @@ public:
return ret;
}

/*
* bigint multiplication: the resulting integer has as many digits
* as the sum of the two operands.
*/
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;
}

/*
* bigint equality operator: just use memcmp.
* FIXME: we could easily support operands of different sizes.
@@ -274,6 +314,22 @@ public:
return !(*this > x);
}

void print() const
{
printf("0x");

int n = (bits_per_digit * N + 31) / 32;
while (n > 1 && get_uint32(n) == 0)
--n;

if (n > 0)
printf("%x", get_uint32(--n));
while (n--)
printf("%08x", get_uint32(n));

printf("\n");
}

private:
/* Allow other types of bigints to access our private members */
template<unsigned int, typename> friend class bigint;
@@ -282,7 +338,22 @@ private:
{
if (N < 1)
return false;
return (m_digits[N - 1] & ((T)1 << (bits_per_digit - 1))) != 0;
return (m_digits[N - 1] >> (bits_per_digit - 1)) != 0;
}

inline uint32_t get_uint32(int offset) const
{
unsigned int bit = offset * 32;
unsigned int digit_index = bit / bits_per_digit;
unsigned int bit_index = bit % bits_per_digit;

if (digit_index >= N)
return 0;

uint32_t ret = m_digits[digit_index] >> bit_index;
if (bits_per_digit - bit_index < 32 && digit_index < N - 1)
ret |= m_digits[digit_index + 1] << (bits_per_digit - bit_index);
return ret;
}

T m_digits[N];


Loading…
Cancel
Save