stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
/* boost random/detail/polynomial.hpp header file
|
||||
*
|
||||
* Copyright Steven Watanabe 2014
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org for most recent version including documentation.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RANDOM_DETAIL_POLYNOMIAL_HPP
|
||||
#define BOOST_RANDOM_DETAIL_POLYNOMIAL_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace random {
|
||||
namespace detail {
|
||||
|
||||
class polynomial_ops {
|
||||
public:
|
||||
typedef unsigned long digit_t;
|
||||
|
||||
static void add(std::size_t size, const digit_t * lhs,
|
||||
const digit_t * rhs, digit_t * output)
|
||||
{
|
||||
for(std::size_t i = 0; i < size; ++i) {
|
||||
output[i] = lhs[i] ^ rhs[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void add_shifted_inplace(std::size_t size, const digit_t * lhs,
|
||||
digit_t * output, std::size_t shift)
|
||||
{
|
||||
if(shift == 0) {
|
||||
add(size, lhs, output, output);
|
||||
return;
|
||||
}
|
||||
std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
digit_t prev = 0;
|
||||
for(std::size_t i = 0; i < size; ++i) {
|
||||
digit_t tmp = lhs[i];
|
||||
output[i] ^= (tmp << shift) | (prev >> (bits-shift));
|
||||
prev = tmp;
|
||||
}
|
||||
output[size] ^= (prev >> (bits-shift));
|
||||
}
|
||||
|
||||
static void multiply_simple(std::size_t size, const digit_t * lhs,
|
||||
const digit_t * rhs, digit_t * output)
|
||||
{
|
||||
std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
for(std::size_t i = 0; i < 2*size; ++i) {
|
||||
output[i] = 0;
|
||||
}
|
||||
for(std::size_t i = 0; i < size; ++i) {
|
||||
for(std::size_t j = 0; j < bits; ++j) {
|
||||
if((lhs[i] & (digit_t(1) << j)) != 0) {
|
||||
add_shifted_inplace(size, rhs, output + i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// memory requirements: (size - cutoff) * 4 + next_smaller
|
||||
static void multiply_karatsuba(std::size_t size,
|
||||
const digit_t * lhs, const digit_t * rhs,
|
||||
digit_t * output)
|
||||
{
|
||||
if(size < 64) {
|
||||
multiply_simple(size, lhs, rhs, output);
|
||||
return;
|
||||
}
|
||||
// split in half
|
||||
std::size_t cutoff = size/2;
|
||||
multiply_karatsuba(cutoff, lhs, rhs, output);
|
||||
multiply_karatsuba(size - cutoff, lhs + cutoff, rhs + cutoff,
|
||||
output + cutoff*2);
|
||||
std::vector<digit_t> local1(size - cutoff);
|
||||
std::vector<digit_t> local2(size - cutoff);
|
||||
// combine the digits for the inner multiply
|
||||
add(cutoff, lhs, lhs + cutoff, &local1[0]);
|
||||
if(size & 1) local1[cutoff] = lhs[size - 1];
|
||||
add(cutoff, rhs + cutoff, rhs, &local2[0]);
|
||||
if(size & 1) local2[cutoff] = rhs[size - 1];
|
||||
std::vector<digit_t> local3((size - cutoff) * 2);
|
||||
multiply_karatsuba(size - cutoff, &local1[0], &local2[0], &local3[0]);
|
||||
add(cutoff * 2, output, &local3[0], &local3[0]);
|
||||
add((size - cutoff) * 2, output + cutoff*2, &local3[0], &local3[0]);
|
||||
// Finally, add the inner result
|
||||
add((size - cutoff) * 2, output + cutoff, &local3[0], output + cutoff);
|
||||
}
|
||||
|
||||
static void multiply_add_karatsuba(std::size_t size,
|
||||
const digit_t * lhs, const digit_t * rhs,
|
||||
digit_t * output)
|
||||
{
|
||||
std::vector<digit_t> buf(size * 2);
|
||||
multiply_karatsuba(size, lhs, rhs, &buf[0]);
|
||||
add(size * 2, &buf[0], output, output);
|
||||
}
|
||||
|
||||
static void multiply(const digit_t * lhs, std::size_t lhs_size,
|
||||
const digit_t * rhs, std::size_t rhs_size,
|
||||
digit_t * output)
|
||||
{
|
||||
std::fill_n(output, lhs_size + rhs_size, digit_t(0));
|
||||
multiply_add(lhs, lhs_size, rhs, rhs_size, output);
|
||||
}
|
||||
|
||||
static void multiply_add(const digit_t * lhs, std::size_t lhs_size,
|
||||
const digit_t * rhs, std::size_t rhs_size,
|
||||
digit_t * output)
|
||||
{
|
||||
// split into pieces that can be passed to
|
||||
// karatsuba multiply.
|
||||
while(lhs_size != 0) {
|
||||
if(lhs_size < rhs_size) {
|
||||
std::swap(lhs, rhs);
|
||||
std::swap(lhs_size, rhs_size);
|
||||
}
|
||||
|
||||
multiply_add_karatsuba(rhs_size, lhs, rhs, output);
|
||||
|
||||
lhs += rhs_size;
|
||||
lhs_size -= rhs_size;
|
||||
output += rhs_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_bits(const digit_t * x, std::size_t low, std::size_t high,
|
||||
digit_t * out)
|
||||
{
|
||||
const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
std::size_t offset = low/bits;
|
||||
x += offset;
|
||||
low -= offset*bits;
|
||||
high -= offset*bits;
|
||||
std::size_t n = (high-low)/bits;
|
||||
if(low == 0) {
|
||||
for(std::size_t i = 0; i < n; ++i) {
|
||||
out[i] = x[i];
|
||||
}
|
||||
} else {
|
||||
for(std::size_t i = 0; i < n; ++i) {
|
||||
out[i] = (x[i] >> low) | (x[i+1] << (bits-low));
|
||||
}
|
||||
}
|
||||
if((high-low)%bits) {
|
||||
digit_t low_mask = (digit_t(1) << ((high-low)%bits)) - 1;
|
||||
digit_t result = (x[n] >> low);
|
||||
if(low != 0 && (n+1)*bits < high) {
|
||||
result |= (x[n+1] << (bits-low));
|
||||
}
|
||||
out[n] = (result & low_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void shift_left(digit_t * val, std::size_t size, std::size_t shift)
|
||||
{
|
||||
const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
BOOST_ASSERT(shift > 0);
|
||||
BOOST_ASSERT(shift < bits);
|
||||
digit_t prev = 0;
|
||||
for(std::size_t i = 0; i < size; ++i) {
|
||||
digit_t tmp = val[i];
|
||||
val[i] = (prev >> (bits - shift)) | (val[i] << shift);
|
||||
prev = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static digit_t sqr(digit_t val) {
|
||||
const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
digit_t mask = (digit_t(1) << bits/2) - 1;
|
||||
for(std::size_t i = bits; i > 1; i /= 2) {
|
||||
val = ((val & ~mask) << i/2) | (val & mask);
|
||||
mask = mask & (mask >> i/4);
|
||||
mask = mask | (mask << i/2);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void sqr(digit_t * val, std::size_t size)
|
||||
{
|
||||
const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
digit_t mask = (digit_t(1) << bits/2) - 1;
|
||||
for(std::size_t i = 0; i < size; ++i) {
|
||||
digit_t x = val[size - i - 1];
|
||||
val[(size - i - 1) * 2] = sqr(x & mask);
|
||||
val[(size - i - 1) * 2 + 1] = sqr(x >> bits/2);
|
||||
}
|
||||
}
|
||||
|
||||
// optimized for the case when the modulus has few bits set.
|
||||
struct sparse_mod {
|
||||
sparse_mod(const digit_t * divisor, std::size_t divisor_bits)
|
||||
{
|
||||
const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
_remainder_bits = divisor_bits - 1;
|
||||
for(std::size_t i = 0; i < divisor_bits; ++i) {
|
||||
if(divisor[i/bits] & (digit_t(1) << i%bits)) {
|
||||
_bit_indices.push_back(i);
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT(_bit_indices.back() == divisor_bits - 1);
|
||||
_bit_indices.pop_back();
|
||||
if(_bit_indices.empty()) {
|
||||
_block_bits = divisor_bits;
|
||||
_lower_bits = 0;
|
||||
} else {
|
||||
_block_bits = divisor_bits - _bit_indices.back() - 1;
|
||||
_lower_bits = _bit_indices.back() + 1;
|
||||
}
|
||||
|
||||
_partial_quotient.resize((_block_bits + bits - 1)/bits);
|
||||
}
|
||||
void operator()(digit_t * dividend, std::size_t dividend_bits)
|
||||
{
|
||||
const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
while(dividend_bits > _remainder_bits) {
|
||||
std::size_t block_start = (std::max)(dividend_bits - _block_bits, _remainder_bits);
|
||||
std::size_t block_size = (dividend_bits - block_start + bits - 1) / bits;
|
||||
copy_bits(dividend, block_start, dividend_bits, &_partial_quotient[0]);
|
||||
for(std::size_t i = 0; i < _bit_indices.size(); ++i) {
|
||||
std::size_t pos = _bit_indices[i] + block_start - _remainder_bits;
|
||||
add_shifted_inplace(block_size, &_partial_quotient[0], dividend + pos/bits, pos%bits);
|
||||
}
|
||||
add_shifted_inplace(block_size, &_partial_quotient[0], dividend + block_start/bits, block_start%bits);
|
||||
dividend_bits = block_start;
|
||||
}
|
||||
}
|
||||
std::vector<digit_t> _partial_quotient;
|
||||
std::size_t _remainder_bits;
|
||||
std::size_t _block_bits;
|
||||
std::size_t _lower_bits;
|
||||
std::vector<std::size_t> _bit_indices;
|
||||
};
|
||||
|
||||
// base should have the same number of bits as mod
|
||||
// base, and mod should both be able to hold a power
|
||||
// of 2 >= mod_bits. out needs to be twice as large.
|
||||
static void mod_pow_x(boost::uintmax_t exponent, const digit_t * mod, std::size_t mod_bits, digit_t * out)
|
||||
{
|
||||
const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
const std::size_t n = (mod_bits + bits - 1) / bits;
|
||||
const std::size_t highbit = mod_bits - 1;
|
||||
if(exponent == 0) {
|
||||
out[0] = 1;
|
||||
std::fill_n(out + 1, n - 1, digit_t(0));
|
||||
return;
|
||||
}
|
||||
boost::uintmax_t i = std::numeric_limits<boost::uintmax_t>::digits - 1;
|
||||
while(((boost::uintmax_t(1) << i) & exponent) == 0) {
|
||||
--i;
|
||||
}
|
||||
out[0] = 2;
|
||||
std::fill_n(out + 1, n - 1, digit_t(0));
|
||||
sparse_mod m(mod, mod_bits);
|
||||
while(i--) {
|
||||
sqr(out, n);
|
||||
m(out, 2 * mod_bits - 1);
|
||||
if((boost::uintmax_t(1) << i) & exponent) {
|
||||
shift_left(out, n, 1);
|
||||
if(out[highbit / bits] & (digit_t(1) << highbit%bits))
|
||||
add(n, out, mod, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class polynomial
|
||||
{
|
||||
typedef polynomial_ops::digit_t digit_t;
|
||||
public:
|
||||
polynomial() : _size(0) {}
|
||||
class reference {
|
||||
public:
|
||||
reference(digit_t &value, int idx)
|
||||
: _value(value), _idx(idx) {}
|
||||
operator bool() const { return (_value & (digit_t(1) << _idx)) != 0; }
|
||||
reference& operator=(bool b)
|
||||
{
|
||||
if(b) {
|
||||
_value |= (digit_t(1) << _idx);
|
||||
} else {
|
||||
_value &= ~(digit_t(1) << _idx);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
reference &operator^=(bool b)
|
||||
{
|
||||
_value ^= (digit_t(b) << _idx);
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference &operator=(const reference &other)
|
||||
{
|
||||
return *this = static_cast<bool>(other);
|
||||
}
|
||||
private:
|
||||
digit_t &_value;
|
||||
int _idx;
|
||||
};
|
||||
reference operator[](std::size_t i)
|
||||
{
|
||||
static const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
ensure_bit(i);
|
||||
return reference(_storage[i/bits], i%bits);
|
||||
}
|
||||
bool operator[](std::size_t i) const
|
||||
{
|
||||
static const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
if(i < size())
|
||||
return (_storage[i/bits] & (digit_t(1) << (i%bits))) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
std::size_t size() const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
void resize(std::size_t n)
|
||||
{
|
||||
static const std::size_t bits = std::numeric_limits<digit_t>::digits;
|
||||
_storage.resize((n + bits - 1)/bits);
|
||||
// clear the high order bits in case we're shrinking.
|
||||
if(n%bits) {
|
||||
_storage.back() &= ((digit_t(1) << (n%bits)) - 1);
|
||||
}
|
||||
_size = n;
|
||||
}
|
||||
friend polynomial operator*(const polynomial &lhs, const polynomial &rhs);
|
||||
friend polynomial mod_pow_x(boost::uintmax_t exponent, polynomial mod);
|
||||
private:
|
||||
std::vector<polynomial_ops::digit_t> _storage;
|
||||
std::size_t _size;
|
||||
void ensure_bit(std::size_t i)
|
||||
{
|
||||
if(i >= size()) {
|
||||
resize(i + 1);
|
||||
}
|
||||
}
|
||||
void normalize()
|
||||
{
|
||||
while(size() && (*this)[size() - 1] == 0)
|
||||
resize(size() - 1);
|
||||
}
|
||||
};
|
||||
|
||||
inline polynomial operator*(const polynomial &lhs, const polynomial &rhs)
|
||||
{
|
||||
polynomial result;
|
||||
result._storage.resize(lhs._storage.size() + rhs._storage.size());
|
||||
polynomial_ops::multiply(&lhs._storage[0], lhs._storage.size(),
|
||||
&rhs._storage[0], rhs._storage.size(),
|
||||
&result._storage[0]);
|
||||
result._size = lhs._size + rhs._size;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline polynomial mod_pow_x(boost::uintmax_t exponent, polynomial mod)
|
||||
{
|
||||
polynomial result;
|
||||
mod.normalize();
|
||||
std::size_t mod_size = mod.size();
|
||||
result._storage.resize(mod._storage.size() * 2);
|
||||
result._size = mod.size() * 2;
|
||||
polynomial_ops::mod_pow_x(exponent, &mod._storage[0], mod_size, &result._storage[0]);
|
||||
result.resize(mod.size() - 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_RANDOM_DETAIL_POLYNOMIAL_HPP
|
||||
Reference in New Issue
Block a user