Skip to content

Commit

Permalink
Fix integer distributions for multiprecision support, and add support…
Browse files Browse the repository at this point in the history
… for one multiprecision generator (independent_bits_engine).

Added test case for multiprecision integers.
  • Loading branch information
jzmaddock committed Mar 14, 2015
1 parent ef63274 commit d4514f1
Show file tree
Hide file tree
Showing 11 changed files with 434 additions and 56 deletions.
18 changes: 9 additions & 9 deletions include/boost/random/detail/seed_impl.hpp
Expand Up @@ -19,9 +19,7 @@
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/integer/integer_mask.hpp>
#include <boost/integer/static_log2.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/random/traits.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
Expand Down Expand Up @@ -55,8 +53,8 @@ struct const_pow_impl
template<class T>
static T call(T arg, int n, T result)
{
return const_pow_impl<N / 2>::call(arg * arg, n / 2,
n%2 == 0? result : result * arg);
return const_pow_impl<N / 2>::call(T(arg * arg), n / 2,
n%2 == 0? result : T(result * arg));
}
};

Expand Down Expand Up @@ -135,7 +133,7 @@ template<class Engine, class Iter>
void generate_from_int(Engine& eng, Iter begin, Iter end)
{
typedef typename Engine::result_type IntType;
typedef typename boost::make_unsigned<IntType>::type unsigned_type;
typedef typename boost::random::traits::make_unsigned<IntType>::type unsigned_type;
int remaining_bits = 0;
boost::uint_least32_t saved_bits = 0;
unsigned_type range = boost::random::detail::subtract<IntType>()((eng.max)(), (eng.min)());
Expand Down Expand Up @@ -219,7 +217,7 @@ void generate_impl(Engine& eng, Iter first, Iter last, boost::mpl::false_)
template<class Engine, class Iter>
void generate(Engine& eng, Iter first, Iter last)
{
return detail::generate_impl(eng, first, last, boost::is_integral<typename Engine::result_type>());
return detail::generate_impl(eng, first, last, boost::random::traits::is_integral<typename Engine::result_type>());
}


Expand Down Expand Up @@ -281,6 +279,7 @@ void seed_array_int_impl(SeedSeq& seq, UIntType (&x)[n])
template<int w, std::size_t n, class SeedSeq, class IntType>
inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::true_)
{
BOOST_STATIC_ASSERT_MSG(boost::is_integral<IntType>::value, "Sorry but this routine has not been ported to non built-in integers as it relies on a reinterpret_cast.");
typedef typename boost::make_unsigned<IntType>::type unsigned_array[n];
seed_array_int_impl<w>(seq, reinterpret_cast<unsigned_array&>(x));
}
Expand All @@ -294,7 +293,7 @@ inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::false
template<int w, std::size_t n, class SeedSeq, class IntType>
inline void seed_array_int(SeedSeq& seq, IntType (&x)[n])
{
seed_array_int_impl<w>(seq, x, boost::is_signed<IntType>());
seed_array_int_impl<w>(seq, x, boost::random::traits::is_signed<IntType>());
}

template<int w, std::size_t n, class Iter, class UIntType>
Expand All @@ -315,6 +314,7 @@ void fill_array_int_impl(Iter& first, Iter last, UIntType (&x)[n])
template<int w, std::size_t n, class Iter, class IntType>
inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost::mpl::true_)
{
BOOST_STATIC_ASSERT_MSG(boost::is_integral<IntType>::value, "Sorry but this routine has not been ported to non built-in integers as it relies on a reinterpret_cast.");
typedef typename boost::make_unsigned<IntType>::type unsigned_array[n];
fill_array_int_impl<w>(first, last, reinterpret_cast<unsigned_array&>(x));
}
Expand All @@ -328,7 +328,7 @@ inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost::
template<int w, std::size_t n, class Iter, class IntType>
inline void fill_array_int(Iter& first, Iter last, IntType (&x)[n])
{
fill_array_int_impl<w>(first, last, x, boost::is_signed<IntType>());
fill_array_int_impl<w>(first, last, x, boost::random::traits::is_signed<IntType>());
}

template<int w, std::size_t n, class RealType>
Expand Down
10 changes: 5 additions & 5 deletions include/boost/random/detail/signed_unsigned_tools.hpp
Expand Up @@ -13,7 +13,7 @@

#include <boost/limits.hpp>
#include <boost/config.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/random/traits.hpp>

namespace boost {
namespace random {
Expand All @@ -24,7 +24,7 @@ namespace detail {
* Compute x - y, we know that x >= y, return an unsigned value.
*/

template<class T, bool sgn = std::numeric_limits<T>::is_signed>
template<class T, bool sgn = std::numeric_limits<T>::is_signed && std::numeric_limits<T>::is_bounded>
struct subtract { };

template<class T>
Expand All @@ -37,7 +37,7 @@ struct subtract<T, /* signed */ false>
template<class T>
struct subtract<T, /* signed */ true>
{
typedef typename make_unsigned<T>::type result_type;
typedef typename boost::random::traits::make_unsigned_or_unbounded<T>::type result_type;
result_type operator()(T x, T y)
{
if (y >= 0) // because x >= y, it follows that x >= 0, too
Expand All @@ -54,11 +54,11 @@ struct subtract<T, /* signed */ true>
* Compute x + y, x is unsigned, result fits in type of "y".
*/

template<class T1, class T2, bool sgn = std::numeric_limits<T2>::is_signed>
template<class T1, class T2, bool sgn = (std::numeric_limits<T2>::is_signed && (std::numeric_limits<T1>::digits >= std::numeric_limits<T2>::digits))>
struct add { };

template<class T1, class T2>
struct add<T1, T2, /* signed */ false>
struct add<T1, T2, /* signed or else T2 has more digits than T1 so the cast always works - needed when T2 is a multiprecision type and T1 is a native integer */ false>
{
typedef T2 result_type;
result_type operator()(T1 x, T2 y) { return T2(x) + y; }
Expand Down
14 changes: 7 additions & 7 deletions include/boost/random/discrete_distribution.hpp
Expand Up @@ -434,10 +434,10 @@ class discrete_distribution {
result = uniform_int_distribution<IntType>((min)(), (max)())(urng);
test = _impl.test(urng);
} while(!_impl.accept(result, test));
if(test < _impl._alias_table[result].first) {
if(test < _impl._alias_table[static_cast<std::size_t>(result)].first) {
return result;
} else {
return(_impl._alias_table[result].second);
return(_impl._alias_table[static_cast<std::size_t>(result)].second);
}
}

Expand Down Expand Up @@ -495,7 +495,7 @@ class discrete_distribution {
*/
std::vector<WeightType> probabilities() const
{
std::vector<WeightType> result(_impl._alias_table.size());
std::vector<WeightType> result(_impl._alias_table.size(), static_cast<WeightType>(0));
std::size_t i = 0;
for(typename impl_type::alias_table_t::const_iterator
iter = _impl._alias_table.begin(),
Expand All @@ -504,7 +504,7 @@ class discrete_distribution {
{
WeightType val = iter->first;
result[i] += val;
result[iter->second] += _impl.get_weight(i) - val;
result[static_cast<std::size_t>(iter->second)] += _impl.get_weight(i) - val;
}
impl_type::normalize(result);
return(result);
Expand Down Expand Up @@ -593,7 +593,7 @@ class discrete_distribution {
a_end = above_average.end()
;
while(b_iter != b_end && a_iter != a_end) {
_impl._alias_table[b_iter->second] =
_impl._alias_table[static_cast<std::size_t>(b_iter->second)] =
std::make_pair(b_iter->first, a_iter->second);
a_iter->first -= (_impl.get_weight(b_iter->second) - b_iter->first);
if(a_iter->first < normalized_average) {
Expand All @@ -603,11 +603,11 @@ class discrete_distribution {
}
}
for(; b_iter != b_end; ++b_iter) {
_impl._alias_table[b_iter->second].first =
_impl._alias_table[static_cast<std::size_t>(b_iter->second)].first =
_impl.get_weight(b_iter->second);
}
for(; a_iter != a_end; ++a_iter) {
_impl._alias_table[a_iter->second].first =
_impl._alias_table[static_cast<std::size_t>(a_iter->second)].first =
_impl.get_weight(a_iter->second);
}
}
Expand Down
29 changes: 20 additions & 9 deletions include/boost/random/independent_bits.hpp
Expand Up @@ -21,7 +21,7 @@
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/integer/integer_mask.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/random/traits.hpp>
#include <boost/random/detail/config.hpp>
#include <boost/random/detail/integer_log2.hpp>
#include <boost/random/detail/operators.hpp>
Expand All @@ -46,6 +46,7 @@ class independent_bits_engine
public:
typedef Engine base_type;
typedef UIntType result_type;
typedef typename Engine::result_type base_result_type;

// Required by old Boost.Random concept
BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
Expand All @@ -55,7 +56,7 @@ class independent_bits_engine
{ return 0; }
/** Returns the largest value that the generator can produce. */
static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
{ return boost::low_bits_mask_t<w>::sig_bits; }
{ return max_imp(boost::is_integral<UIntType>()); }

/**
* Constructs an @c independent_bits_engine using the
Expand All @@ -68,7 +69,7 @@ class independent_bits_engine
* the constructor argument for both base generators.
*/
BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(independent_bits_engine,
result_type, seed_arg)
base_result_type, seed_arg)
{
_base.seed(seed_arg);
}
Expand Down Expand Up @@ -108,7 +109,7 @@ class independent_bits_engine
* seed for the base generator.
*/
BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(independent_bits_engine,
result_type, seed_arg)
base_result_type, seed_arg)
{ _base.seed(seed_arg); }

/**
Expand Down Expand Up @@ -139,7 +140,7 @@ class independent_bits_engine
// every time, both msvc and gcc can propagate
// constants, resolving this at compile time.
base_unsigned range =
detail::subtract<base_result>()((_base.max)(), (_base.min)());
detail::subtract<base_result_type>()((_base.max)(), (_base.min)());
std::size_t m =
(range == (std::numeric_limits<base_unsigned>::max)()) ?
std::numeric_limits<base_unsigned>::digits :
Expand All @@ -161,14 +162,14 @@ class independent_bits_engine
for(std::size_t k = 0; k < n0; ++k) {
base_unsigned u;
do {
u = detail::subtract<base_result>()(_base(), (_base.min)());
u = detail::subtract<base_result_type>()(_base(), (_base.min)());
} while(u > base_unsigned(y0 - 1));
S = (S << w0) + (u & y0_mask);
}
for(std::size_t k = 0; k < (n - n0); ++k) {
base_unsigned u;
do {
u = detail::subtract<base_result>()(_base(), (_base.min)());
u = detail::subtract<base_result_type>()(_base(), (_base.min)());
} while(u > base_unsigned(y1 - 1));
S = (S << (w0 + 1)) + (u & y1_mask);
}
Expand Down Expand Up @@ -226,8 +227,18 @@ class independent_bits_engine
private:

/// \cond show_private
typedef typename base_type::result_type base_result;
typedef typename make_unsigned<base_result>::type base_unsigned;
typedef typename boost::random::traits::make_unsigned<base_result_type>::type base_unsigned;

static UIntType max_imp(const boost::true_type&)
{
return boost::low_bits_mask_t<w>::sig_bits;
}
static UIntType max_imp(const boost::false_type&)
{
// We have a multiprecision integer type:
BOOST_STATIC_ASSERT(std::numeric_limits<UIntType>::is_specialized);
return w < std::numeric_limits<UIntType>::digits ? UIntType((UIntType(1) << w) - 1) : UIntType((((UIntType(1) << (w - 1)) - 1) << 1) | 1u);
}

void calc_params(
std::size_t n, base_unsigned range,
Expand Down
2 changes: 1 addition & 1 deletion include/boost/random/piecewise_constant_distribution.hpp
Expand Up @@ -409,7 +409,7 @@ class piecewise_constant_distribution {
void param(const param_type& parm)
{
std::vector<RealType> new_intervals(parm._intervals);
typedef discrete_distribution<std::size_t, RealType> bins_type;
typedef discrete_distribution<std::size_t, WeightType> bins_type;
typename bins_type::param_type bins_param(parm._weights);
_bins.param(bins_param);
_intervals.swap(new_intervals);
Expand Down
3 changes: 2 additions & 1 deletion include/boost/random/piecewise_linear_distribution.hpp
Expand Up @@ -487,14 +487,15 @@ class piecewise_linear_distribution {
void init(const std::vector<RealType>& intervals_arg,
const std::vector<RealType>& weights_arg)
{
using std::abs;
std::vector<RealType> bin_weights;
bin_weights.reserve((intervals_arg.size() - 1) * 2);
for(std::size_t i = 0; i < intervals_arg.size() - 1; ++i) {
RealType width = intervals_arg[i + 1] - intervals_arg[i];
RealType w1 = weights_arg[i];
RealType w2 = weights_arg[i + 1];
bin_weights.push_back((std::min)(w1, w2) * width);
bin_weights.push_back(std::abs(w1 - w2) * width / 2);
bin_weights.push_back(abs(w1 - w2) * width / 2);
}
typedef discrete_distribution<std::size_t, RealType> bins_type;
typename bins_type::param_type bins_param(bin_weights);
Expand Down
2 changes: 1 addition & 1 deletion include/boost/random/shuffle_order.hpp
Expand Up @@ -130,7 +130,7 @@ class shuffle_order_engine
result_type operator()() {
// calculating the range every time may seem wasteful. However, this
// makes the information locally available for the optimizer.
typedef typename make_unsigned<result_type>::type base_unsigned;
typedef typename boost::random::traits::make_unsigned<result_type>::type base_unsigned;
const base_unsigned brange =
detail::subtract<result_type>()((max)(), (min)());
const base_unsigned off =
Expand Down

0 comments on commit d4514f1

Please sign in to comment.