diff --git a/include/boost/random/detail/seed_impl.hpp b/include/boost/random/detail/seed_impl.hpp index 2451dbe521..918a294457 100644 --- a/include/boost/random/detail/seed_impl.hpp +++ b/include/boost/random/detail/seed_impl.hpp @@ -19,9 +19,7 @@ #include #include #include -#include -#include -#include +#include #include #include #include @@ -55,8 +53,8 @@ struct const_pow_impl template static T call(T arg, int n, T result) { - return const_pow_impl::call(arg * arg, n / 2, - n%2 == 0? result : result * arg); + return const_pow_impl::call(T(arg * arg), n / 2, + n%2 == 0? result : T(result * arg)); } }; @@ -135,7 +133,7 @@ template void generate_from_int(Engine& eng, Iter begin, Iter end) { typedef typename Engine::result_type IntType; - typedef typename boost::make_unsigned::type unsigned_type; + typedef typename boost::random::traits::make_unsigned::type unsigned_type; int remaining_bits = 0; boost::uint_least32_t saved_bits = 0; unsigned_type range = boost::random::detail::subtract()((eng.max)(), (eng.min)()); @@ -219,7 +217,7 @@ void generate_impl(Engine& eng, Iter first, Iter last, boost::mpl::false_) template void generate(Engine& eng, Iter first, Iter last) { - return detail::generate_impl(eng, first, last, boost::is_integral()); + return detail::generate_impl(eng, first, last, boost::random::traits::is_integral()); } @@ -281,6 +279,7 @@ void seed_array_int_impl(SeedSeq& seq, UIntType (&x)[n]) template inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::true_) { + BOOST_STATIC_ASSERT_MSG(boost::is_integral::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::type unsigned_array[n]; seed_array_int_impl(seq, reinterpret_cast(x)); } @@ -294,7 +293,7 @@ inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::false template inline void seed_array_int(SeedSeq& seq, IntType (&x)[n]) { - seed_array_int_impl(seq, x, boost::is_signed()); + seed_array_int_impl(seq, x, boost::random::traits::is_signed()); } template @@ -315,6 +314,7 @@ void fill_array_int_impl(Iter& first, Iter last, UIntType (&x)[n]) template inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost::mpl::true_) { + BOOST_STATIC_ASSERT_MSG(boost::is_integral::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::type unsigned_array[n]; fill_array_int_impl(first, last, reinterpret_cast(x)); } @@ -328,7 +328,7 @@ inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost:: template inline void fill_array_int(Iter& first, Iter last, IntType (&x)[n]) { - fill_array_int_impl(first, last, x, boost::is_signed()); + fill_array_int_impl(first, last, x, boost::random::traits::is_signed()); } template diff --git a/include/boost/random/detail/signed_unsigned_tools.hpp b/include/boost/random/detail/signed_unsigned_tools.hpp index 988cfb84db..1979908a31 100644 --- a/include/boost/random/detail/signed_unsigned_tools.hpp +++ b/include/boost/random/detail/signed_unsigned_tools.hpp @@ -13,7 +13,7 @@ #include #include -#include +#include namespace boost { namespace random { @@ -24,7 +24,7 @@ namespace detail { * Compute x - y, we know that x >= y, return an unsigned value. */ -template::is_signed> +template::is_signed && std::numeric_limits::is_bounded> struct subtract { }; template @@ -37,7 +37,7 @@ struct subtract template struct subtract { - typedef typename make_unsigned::type result_type; + typedef typename boost::random::traits::make_unsigned_or_unbounded::type result_type; result_type operator()(T x, T y) { if (y >= 0) // because x >= y, it follows that x >= 0, too @@ -54,11 +54,11 @@ struct subtract * Compute x + y, x is unsigned, result fits in type of "y". */ -template::is_signed> +template::is_signed && (std::numeric_limits::digits >= std::numeric_limits::digits))> struct add { }; template -struct add +struct add { typedef T2 result_type; result_type operator()(T1 x, T2 y) { return T2(x) + y; } diff --git a/include/boost/random/discrete_distribution.hpp b/include/boost/random/discrete_distribution.hpp index 6407272093..3d14d4a02c 100644 --- a/include/boost/random/discrete_distribution.hpp +++ b/include/boost/random/discrete_distribution.hpp @@ -434,10 +434,10 @@ class discrete_distribution { result = uniform_int_distribution((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(result)].first) { return result; } else { - return(_impl._alias_table[result].second); + return(_impl._alias_table[static_cast(result)].second); } } @@ -495,7 +495,7 @@ class discrete_distribution { */ std::vector probabilities() const { - std::vector result(_impl._alias_table.size()); + std::vector result(_impl._alias_table.size(), static_cast(0)); std::size_t i = 0; for(typename impl_type::alias_table_t::const_iterator iter = _impl._alias_table.begin(), @@ -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(iter->second)] += _impl.get_weight(i) - val; } impl_type::normalize(result); return(result); @@ -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(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) { @@ -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(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(a_iter->second)].first = _impl.get_weight(a_iter->second); } } diff --git a/include/boost/random/independent_bits.hpp b/include/boost/random/independent_bits.hpp index 5ff52b80ff..dec63b3f46 100644 --- a/include/boost/random/independent_bits.hpp +++ b/include/boost/random/independent_bits.hpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -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); @@ -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::sig_bits; } + { return max_imp(boost::is_integral()); } /** * Constructs an @c independent_bits_engine using the @@ -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); } @@ -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); } /** @@ -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.max)(), (_base.min)()); + detail::subtract()((_base.max)(), (_base.min)()); std::size_t m = (range == (std::numeric_limits::max)()) ? std::numeric_limits::digits : @@ -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(), (_base.min)()); + u = detail::subtract()(_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(), (_base.min)()); + u = detail::subtract()(_base(), (_base.min)()); } while(u > base_unsigned(y1 - 1)); S = (S << (w0 + 1)) + (u & y1_mask); } @@ -226,8 +227,18 @@ class independent_bits_engine private: /// \cond show_private - typedef typename base_type::result_type base_result; - typedef typename make_unsigned::type base_unsigned; + typedef typename boost::random::traits::make_unsigned::type base_unsigned; + + static UIntType max_imp(const boost::true_type&) + { + return boost::low_bits_mask_t::sig_bits; + } + static UIntType max_imp(const boost::false_type&) + { + // We have a multiprecision integer type: + BOOST_STATIC_ASSERT(std::numeric_limits::is_specialized); + return w < std::numeric_limits::digits ? UIntType((UIntType(1) << w) - 1) : UIntType((((UIntType(1) << (w - 1)) - 1) << 1) | 1u); + } void calc_params( std::size_t n, base_unsigned range, diff --git a/include/boost/random/piecewise_constant_distribution.hpp b/include/boost/random/piecewise_constant_distribution.hpp index 697a374087..488f41c0e3 100644 --- a/include/boost/random/piecewise_constant_distribution.hpp +++ b/include/boost/random/piecewise_constant_distribution.hpp @@ -409,7 +409,7 @@ class piecewise_constant_distribution { void param(const param_type& parm) { std::vector new_intervals(parm._intervals); - typedef discrete_distribution bins_type; + typedef discrete_distribution bins_type; typename bins_type::param_type bins_param(parm._weights); _bins.param(bins_param); _intervals.swap(new_intervals); diff --git a/include/boost/random/piecewise_linear_distribution.hpp b/include/boost/random/piecewise_linear_distribution.hpp index 861cf429c5..541c57fb82 100644 --- a/include/boost/random/piecewise_linear_distribution.hpp +++ b/include/boost/random/piecewise_linear_distribution.hpp @@ -487,6 +487,7 @@ class piecewise_linear_distribution { void init(const std::vector& intervals_arg, const std::vector& weights_arg) { + using std::abs; std::vector bin_weights; bin_weights.reserve((intervals_arg.size() - 1) * 2); for(std::size_t i = 0; i < intervals_arg.size() - 1; ++i) { @@ -494,7 +495,7 @@ class piecewise_linear_distribution { 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 bins_type; typename bins_type::param_type bins_param(bin_weights); diff --git a/include/boost/random/shuffle_order.hpp b/include/boost/random/shuffle_order.hpp index 646c09bafa..54645303e8 100644 --- a/include/boost/random/shuffle_order.hpp +++ b/include/boost/random/shuffle_order.hpp @@ -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::type base_unsigned; + typedef typename boost::random::traits::make_unsigned::type base_unsigned; const base_unsigned brange = detail::subtract()((max)(), (min)()); const base_unsigned off = diff --git a/include/boost/random/traits.hpp b/include/boost/random/traits.hpp new file mode 100644 index 0000000000..975421a4d0 --- /dev/null +++ b/include/boost/random/traits.hpp @@ -0,0 +1,107 @@ +/* boost random/traits.hpp header file + * + * Copyright John Maddock 2015 + * 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. + * + * These traits classes serve two purposes: they are designed to mostly + * work out of the box for multiprecision types (ie number types that are + * C++ class types and not integers or floats from type-traits point of view), + * they are also a potential point of specialization for user-defined + * number types. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_TRAITS_HPP +#define BOOST_RANDOM_TRAITS_HPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace random { +namespace traits { + // \cond show_private + template + struct make_unsigned_imp + { + typedef typename boost::make_unsigned::type type; + }; + template + struct make_unsigned_imp + { + BOOST_STATIC_ASSERT(std::numeric_limits::is_specialized); + BOOST_STATIC_ASSERT(std::numeric_limits::is_signed == false); + BOOST_STATIC_ASSERT(std::numeric_limits::is_integer == true); + typedef T type; + }; + // \endcond + /** \brief Converts the argument type T to an unsigned type. + * + * This trait has a single member `type` which is the unsigned type corresponding to T. + * Note that + * if T is signed, then member `type` *should define a type with one more bit precision than T*. For built-in + * types this trait defaults to `boost::make_unsigned::type`. For user defined types it simply asserts that + * the argument type T is an unsigned integer (using std::numeric_limits). + * User defined specializations may be provided for other cases. + */ + template + struct make_unsigned + // \cond show_private + : public make_unsigned_imp < T, boost::is_integral::value > + // \endcond + {}; + // \cond show_private + template + struct make_unsigned_or_unbounded_imp + { + typedef typename boost::make_unsigned::type type; + }; + template + struct make_unsigned_or_unbounded_imp + { + BOOST_STATIC_ASSERT(std::numeric_limits::is_specialized); + BOOST_STATIC_ASSERT((std::numeric_limits::is_signed == false) || (std::numeric_limits::is_bounded == false)); + BOOST_STATIC_ASSERT(std::numeric_limits::is_integer == true); + typedef T type; + }; + // \endcond + /** \brief Converts the argument type T to either an unsigned type or an unbounded integer type. + * + * This trait has a single member `type` which is either the unsigned type corresponding to T or an unbounded + * integer type. This trait is used to generate types suitable for the calculation of a range: as a result + * if T is signed, then member `type` *should define a type with one more bit precision than T*. For built-in + * types this trait defaults to `boost::make_unsigned::type`. For user defined types it simply asserts that + * the argument type T is either an unbounded integer, or an unsigned one (using std::numeric_limits). + * User defined specializations may be provided for other cases. + */ + template + struct make_unsigned_or_unbounded + // \cond show_private + : public make_unsigned_or_unbounded_imp < T, boost::is_integral::value > + // \endcond + {}; + /** \brief Traits class that indicates whether type T is an integer + */ + template + struct is_integral + : public mpl::bool_::value || (std::numeric_limits::is_integer)> + {}; + /** \brief Traits class that indicates whether type T is a signed integer + */ + template struct is_signed + : public mpl::bool_ < boost::is_signed::value || (std::numeric_limits::is_specialized && std::numeric_limits::is_integer && std::numeric_limits::is_signed)> + {}; + +} +} +} + +#endif diff --git a/include/boost/random/uniform_int_distribution.hpp b/include/boost/random/uniform_int_distribution.hpp index e7ef4b8248..e0d3a9bebc 100644 --- a/include/boost/random/uniform_int_distribution.hpp +++ b/include/boost/random/uniform_int_distribution.hpp @@ -28,9 +28,11 @@ #include #include #include -#include -#include +#include #include +#ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#include +#endif namespace boost { namespace random { @@ -50,10 +52,10 @@ T generate_uniform_int( boost::mpl::true_ /** is_integral */) { typedef T result_type; - typedef typename make_unsigned::type range_type; + typedef typename boost::random::traits::make_unsigned_or_unbounded::type range_type; typedef typename Engine::result_type base_result; - // ranges are always unsigned - typedef typename make_unsigned::type base_unsigned; + // ranges are always unsigned or unbounded + typedef typename boost::random::traits::make_unsigned_or_unbounded::type base_unsigned; const range_type range = random::detail::subtract()(max_value, min_value); const base_result bmin = (eng.min)(); const base_unsigned brange = @@ -112,7 +114,7 @@ T generate_uniform_int( // mult+mult*brange by (2), (3) (4) // Therefore result+(eng()-bmin)*mult < // mult*(brange+1) by (4) - result += static_cast(random::detail::subtract()(eng(), bmin) * mult); + result += static_cast(static_cast(random::detail::subtract()(eng(), bmin)) * mult); // equivalent to (mult * (brange+1)) == range+1, but avoids overflow. if(mult * range_type(brange) == range - mult + 1) { @@ -166,7 +168,7 @@ T generate_uniform_int( static_cast(0), static_cast(range/mult), boost::mpl::true_()); - if((std::numeric_limits::max)() / mult < result_increment) { + if(std::numeric_limits::is_bounded && ((std::numeric_limits::max)() / mult < result_increment)) { // The multiplcation would overflow. Reject immediately. continue; } @@ -184,27 +186,43 @@ T generate_uniform_int( return random::detail::add()(result, min_value); } } else { // brange > range - base_unsigned bucket_size; +#ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + typedef typename mpl::if_c< + std::numeric_limits::is_specialized && std::numeric_limits::is_specialized + && (std::numeric_limits::digits >= std::numeric_limits::digits), + range_type, base_unsigned>::type mixed_range_type; +#else + typedef base_unsigned mixed_range_type; +#endif + + mixed_range_type bucket_size; // it's safe to add 1 to range, as long as we cast it first, // because we know that it is less than brange. However, // we do need to be careful not to cause overflow by adding 1 - // to brange. + // to brange. We use mixed_range_type throughout for mixed + // arithmetic between base_unsigned and range_type - in the case + // that range_type has more bits than base_unsigned it is always + // safe to use range_type for this albeit it may be more effient + // to use base_unsigned. The latter is a narrowing conversion though + // which may be disallowed if range_type is a multiprecision type + // and there are no explicit converison operators. + if(brange == (std::numeric_limits::max)()) { - bucket_size = brange / (static_cast(range)+1); - if(brange % (static_cast(range)+1) == static_cast(range)) { + bucket_size = static_cast(brange) / (static_cast(range)+1); + if(static_cast(brange) % (static_cast(range)+1) == static_cast(range)) { ++bucket_size; } } else { - bucket_size = (brange+1) / (static_cast(range)+1); + bucket_size = static_cast(brange + 1) / (static_cast(range)+1); } for(;;) { - base_unsigned result = + mixed_range_type result = random::detail::subtract()(eng(), bmin); result /= bucket_size; // result and range are non-negative, and result is possibly larger // than range, so the cast is safe - if(result <= static_cast(range)) - return random::detail::add()(result, min_value); + if(result <= static_cast(range)) + return random::detail::add()(result, min_value); } } } @@ -227,7 +245,7 @@ inline T generate_uniform_int(Engine& eng, T min_value, T max_value) { typedef typename Engine::result_type base_result; return generate_uniform_int(eng, min_value, max_value, - boost::is_integral()); + boost::random::traits::is_integral()); } } diff --git a/include/boost/random/uniform_smallint.hpp b/include/boost/random/uniform_smallint.hpp index 96f2fdc2c1..c1afd7fbcd 100644 --- a/include/boost/random/uniform_smallint.hpp +++ b/include/boost/random/uniform_smallint.hpp @@ -30,6 +30,10 @@ #include #include +#ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#include +#endif + namespace boost { namespace random { @@ -194,7 +198,7 @@ class uniform_smallint result_type operator()(Engine& eng) const { typedef typename Engine::result_type base_result; - return generate(eng, boost::is_integral()); + return generate(eng, boost::random::traits::is_integral()); } /** Returns a value uniformly distributed in the range [param.a(), param.b()]. */ @@ -238,20 +242,34 @@ class uniform_smallint // equivalent to (eng() - eng.min()) % (_max - _min + 1) + _min, // but guarantees no overflow. typedef typename Engine::result_type base_result; - typedef typename boost::make_unsigned::type base_unsigned; - typedef typename boost::make_unsigned::type range_type; + typedef typename boost::random::traits::make_unsigned::type base_unsigned; + typedef typename boost::random::traits::make_unsigned_or_unbounded::type range_type; +#ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + typedef typename mpl::if_c< + std::numeric_limits::is_specialized && std::numeric_limits::is_specialized + && (std::numeric_limits::digits >= std::numeric_limits::digits), + range_type, base_unsigned>::type mixed_range_type; +#else + typedef base_unsigned mixed_range_type; +#endif range_type range = random::detail::subtract()(_max, _min); base_unsigned base_range = - random::detail::subtract()((eng.max)(), (eng.min)()); + random::detail::subtract()((eng.max)(), (eng.min)()); base_unsigned val = random::detail::subtract()(eng(), (eng.min)()); if(range >= base_range) { return boost::random::detail::add()( static_cast(val), _min); } else { - base_unsigned modulus = static_cast(range) + 1; + // This involves mixed arithmetic between the base generators range + // type, and the result_type's range type. mixed_range_type is + // normally the same as base_unsigned which is the most efficient + // option, but requires a narrowing explcit cast if result_type + // is a multiprecision type. If no such casts are available then use + // multiprecision arithmetic throughout instead. + mixed_range_type modulus = static_cast(range)+1; return boost::random::detail::add()( - static_cast(val % modulus), _min); + static_cast(val) % modulus, _min); } } @@ -259,7 +277,7 @@ class uniform_smallint result_type generate(Engine& eng, boost::mpl::false_) const { typedef typename Engine::result_type base_result; - typedef typename boost::make_unsigned::type range_type; + typedef typename boost::random::traits::make_unsigned::type range_type; range_type range = random::detail::subtract()(_max, _min); base_result val = boost::uniform_01()(eng); // what is the worst that can possibly happen here? diff --git a/test/multiprecision_int_test.cpp b/test/multiprecision_int_test.cpp new file mode 100644 index 0000000000..c61b0dd8fb --- /dev/null +++ b/test/multiprecision_int_test.cpp @@ -0,0 +1,223 @@ + +/* multiprecision_int_test.cpp +* +* Copyright John Maddock 2015 +* 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) +* +* $Id$ +* +* Tests all integer related generators and distributions with multiprecision types: +* discard_block, independent_bits_engine, random_number_generator, +* xor_combine_engine, uniform_int_distribution, uniform_smallint. +* +* Not supported, but could be with more work (but probably not worth while): +* shuffle_order_engine, binomial_distribution, discrete_distribution, negative_binomial_distribution, +* poisson_distribution +*/ + +#define BOOST_TEST_MAIN +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef boost::mpl::list < + boost::random::independent_bits_engine, + boost::random::independent_bits_engine, + boost::random::independent_bits_engine, + boost::random::independent_bits_engine, + boost::random::independent_bits_engine, + boost::random::discard_block_engine, 20, 10>, + boost::random::discard_block_engine, 20, 10>, + boost::random::discard_block_engine, 20, 10>, + boost::random::discard_block_engine, 20, 10>, + boost::random::discard_block_engine, 20, 10> +> engines; + +BOOST_AUTO_TEST_CASE_TEMPLATE(generator_test, engine_type, engines) +{ + typedef typename engine_type::result_type test_type; + + engine_type gen; + gen.seed(); + test_type a = gen.min(); + test_type b = gen.max(); + BOOST_CHECK(a < b); + a = gen(); + // + // This extracts 32-bit values for use in seeding other sequences, + // not really applicable here, and not functional for signed types anyway. + //gen.generate(&b, &b + 1); + gen.discard(20); + + typename engine_type::base_type base(gen.base()); + + std::stringstream ss; + ss << gen; + engine_type gen2; + ss >> gen2; + BOOST_CHECK(gen == gen2); + gen2(); + BOOST_CHECK(gen != gen2); + // + // construction and seeding: + // + engine_type gen3(0); + gen3.seed(2); +} + +BOOST_AUTO_TEST_CASE(xor_combine_test) +{ + // + // As above but with a few things missing which don't work - for example we have no + // way to drill down and get the seed-type of the underlying generator. + // + typedef boost::random::xor_combine_engine, 512, boost::random::independent_bits_engine, 10> engine_type; + typedef engine_type::result_type test_type; + + engine_type gen; + gen.seed(); + test_type a = gen.min(); + test_type b = gen.max(); + BOOST_CHECK(a < b); + a = gen(); +#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + gen.generate(&b, &b + 1); +#endif + gen.discard(20); + + //typename engine_type::base_type base(gen.base()); + + std::stringstream ss; + ss << gen; + engine_type gen2; + ss >> gen2; + BOOST_CHECK(gen == gen2); + gen2(); + BOOST_CHECK(gen != gen2); + // + // construction and seeding: + // + //engine_type gen3(0); + //gen3.seed(2); +} + +typedef boost::mpl::list < + boost::random::random_number_generator, + boost::random::random_number_generator, + boost::random::random_number_generator +> generators; + + +BOOST_AUTO_TEST_CASE_TEMPLATE(random_number_generator, generator_type, generators) +{ + typedef typename generator_type::result_type result_type; + typedef typename generator_type::base_type base_type; + + result_type lim = 1; + lim <<= 500; + + base_type base; + generator_type gen(base); + + for(unsigned i = 0; i < 100; ++i) + BOOST_CHECK(gen(lim) < lim); +} + +typedef boost::mpl::list < + boost::random::uniform_int_distribution, + boost::random::uniform_int_distribution, + boost::random::uniform_int_distribution, + boost::random::uniform_smallint, + boost::random::uniform_smallint, + boost::random::uniform_smallint +> uniform_distributions; + + +BOOST_AUTO_TEST_CASE_TEMPLATE(distributions, distribution_type, uniform_distributions) +{ + typedef typename distribution_type::result_type result_type; + + result_type a = 20; + result_type b = 1; + b <<= 1000; + + distribution_type d(a, b); + boost::random::mt19937 gen; + + BOOST_CHECK_EQUAL(d.a(), a); + BOOST_CHECK_EQUAL(d.b(), b); + BOOST_CHECK_EQUAL((d.min)(), a); + BOOST_CHECK_EQUAL((d.max)(), b); + + for(unsigned i = 0; i < 200; ++i) + { + result_type r = d(gen); + BOOST_CHECK(r <= b); + BOOST_CHECK(r >= a); + } + + std::stringstream ss; + ss << d; + distribution_type d2; + ss >> d2; + BOOST_CHECK(d == d2); + + boost::random::independent_bits_engine::digits, boost::multiprecision::uint1024_t > big_random; + for(unsigned i = 0; i < 200; ++i) + { + result_type r = d(big_random); + BOOST_CHECK(r <= b); + BOOST_CHECK(r >= a); + } +} + +#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + +typedef boost::mpl::list < + boost::random::discrete_distribution < boost::multiprecision::cpp_int, double>, + boost::random::discrete_distribution +> other_distributions; + + +BOOST_AUTO_TEST_CASE_TEMPLATE(discrete_distributions, distribution_type, other_distributions) +{ + typedef typename distribution_type::result_type result_type; + typedef typename distribution_type::input_type input_type; + + input_type a[] = { 20, 30, 40, 50 }; + + distribution_type d(a, a + 4); + boost::random::mt19937 gen; + + for(unsigned i = 0; i < 200; ++i) + { + result_type r = d(gen); + } + + std::stringstream ss; + ss << std::setprecision(std::numeric_limits::digits10 + 3) << d; + distribution_type d2; + ss >> d2; + BOOST_CHECK(d == d2); + + boost::random::independent_bits_engine::digits, boost::multiprecision::uint1024_t > big_random; + for(unsigned i = 0; i < 200; ++i) + { + result_type r = d(big_random); + } +} + +#endif