Chris@16: /* boost random/detail/seed.hpp header file Chris@16: * Chris@16: * Copyright Steven Watanabe 2009 Chris@16: * Distributed under the Boost Software License, Version 1.0. (See Chris@16: * accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Chris@16: * See http://www.boost.org for most recent version including documentation. Chris@16: * Chris@101: * $Id$ Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_RANDOM_DETAIL_SEED_IMPL_HPP Chris@16: #define BOOST_RANDOM_DETAIL_SEED_IMPL_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace random { Chris@16: namespace detail { Chris@16: Chris@16: // finds the seed type of an engine, given its Chris@16: // result_type. If the result_type is integral Chris@16: // the seed type is the same. If the result_type Chris@16: // is floating point, the seed type is uint32_t Chris@16: template Chris@16: struct seed_type Chris@16: { Chris@16: typedef typename boost::mpl::if_, Chris@16: T, Chris@16: boost::uint32_t Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct const_pow_impl Chris@16: { Chris@16: template Chris@16: static T call(T arg, int n, T result) Chris@16: { Chris@16: return const_pow_impl::call(arg * arg, n / 2, Chris@16: n%2 == 0? result : result * arg); Chris@16: } Chris@16: }; Chris@16: Chris@16: template<> Chris@16: struct const_pow_impl<0> Chris@16: { Chris@16: template Chris@16: static T call(T, int, T result) Chris@16: { Chris@16: return result; Chris@16: } Chris@16: }; Chris@16: Chris@16: // requires N is an upper bound on n Chris@16: template Chris@16: inline T const_pow(T arg, int n) { return const_pow_impl::call(arg, n, T(1)); } Chris@16: Chris@16: template Chris@16: inline T pow2(int n) Chris@16: { Chris@16: typedef unsigned int_type; Chris@16: const int max_bits = std::numeric_limits::digits; Chris@16: T multiplier = T(int_type(1) << (max_bits - 1)) * 2; Chris@16: return (int_type(1) << (n % max_bits)) * Chris@16: const_pow::digits / max_bits>(multiplier, n / max_bits); Chris@16: } Chris@16: Chris@16: template Chris@16: void generate_from_real(Engine& eng, Iter begin, Iter end) Chris@16: { Chris@16: using std::fmod; Chris@16: typedef typename Engine::result_type RealType; Chris@16: const int Bits = detail::generator_bits::value(); Chris@16: int remaining_bits = 0; Chris@16: boost::uint_least32_t saved_bits = 0; Chris@16: RealType multiplier = pow2( Bits); Chris@16: RealType mult32 = RealType(4294967296.0); // 2^32 Chris@16: while(true) { Chris@16: RealType val = eng() * multiplier; Chris@16: int available_bits = Bits; Chris@16: // Make sure the compiler can optimize this out Chris@16: // if it isn't possible. Chris@16: if(Bits < 32 && available_bits < 32 - remaining_bits) { Chris@16: saved_bits |= boost::uint_least32_t(val) << remaining_bits; Chris@16: remaining_bits += Bits; Chris@16: } else { Chris@16: // If Bits < 32, then remaining_bits != 0, since Chris@16: // if remaining_bits == 0, available_bits < 32 - 0, Chris@16: // and we won't get here to begin with. Chris@16: if(Bits < 32 || remaining_bits != 0) { Chris@16: boost::uint_least32_t divisor = Chris@16: (boost::uint_least32_t(1) << (32 - remaining_bits)); Chris@16: boost::uint_least32_t extra_bits = boost::uint_least32_t(fmod(val, mult32)) & (divisor - 1); Chris@16: val = val / divisor; Chris@16: *begin++ = saved_bits | (extra_bits << remaining_bits); Chris@16: if(begin == end) return; Chris@16: available_bits -= 32 - remaining_bits; Chris@16: remaining_bits = 0; Chris@16: } Chris@16: // If Bits < 32 we should never enter this loop Chris@16: if(Bits >= 32) { Chris@16: for(; available_bits >= 32; available_bits -= 32) { Chris@16: boost::uint_least32_t word = boost::uint_least32_t(fmod(val, mult32)); Chris@16: val /= mult32; Chris@16: *begin++ = word; Chris@16: if(begin == end) return; Chris@16: } Chris@16: } Chris@16: remaining_bits = available_bits; Chris@16: saved_bits = static_cast(val); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void generate_from_int(Engine& eng, Iter begin, Iter end) Chris@16: { Chris@16: typedef typename Engine::result_type IntType; Chris@16: typedef typename boost::make_unsigned::type unsigned_type; Chris@16: int remaining_bits = 0; Chris@16: boost::uint_least32_t saved_bits = 0; Chris@16: unsigned_type range = boost::random::detail::subtract()((eng.max)(), (eng.min)()); Chris@16: Chris@16: int bits = Chris@16: (range == (std::numeric_limits::max)()) ? Chris@16: std::numeric_limits::digits : Chris@16: detail::integer_log2(range + 1); Chris@16: Chris@16: { Chris@16: int discarded_bits = detail::integer_log2(bits); Chris@16: unsigned_type excess = (range + 1) >> (bits - discarded_bits); Chris@16: if(excess != 0) { Chris@16: int extra_bits = detail::integer_log2((excess - 1) ^ excess); Chris@16: bits = bits - discarded_bits + extra_bits; Chris@16: } Chris@16: } Chris@16: Chris@16: unsigned_type mask = (static_cast(2) << (bits - 1)) - 1; Chris@16: unsigned_type limit = ((range + 1) & ~mask) - 1; Chris@16: Chris@16: while(true) { Chris@16: unsigned_type val; Chris@16: do { Chris@16: val = boost::random::detail::subtract()(eng(), (eng.min)()); Chris@16: } while(limit != range && val > limit); Chris@16: val &= mask; Chris@16: int available_bits = bits; Chris@16: if(available_bits == 32) { Chris@16: *begin++ = static_cast(val) & 0xFFFFFFFFu; Chris@16: if(begin == end) return; Chris@16: } else if(available_bits % 32 == 0) { Chris@16: for(int i = 0; i < available_bits / 32; ++i) { Chris@16: boost::uint_least32_t word = boost::uint_least32_t(val) & 0xFFFFFFFFu; Chris@101: int suppress_warning = (bits >= 32); Chris@101: BOOST_ASSERT(suppress_warning == 1); Chris@101: val >>= (32 * suppress_warning); Chris@16: *begin++ = word; Chris@16: if(begin == end) return; Chris@16: } Chris@16: } else if(bits < 32 && available_bits < 32 - remaining_bits) { Chris@16: saved_bits |= boost::uint_least32_t(val) << remaining_bits; Chris@16: remaining_bits += bits; Chris@16: } else { Chris@16: if(bits < 32 || remaining_bits != 0) { Chris@16: boost::uint_least32_t extra_bits = boost::uint_least32_t(val) & ((boost::uint_least32_t(1) << (32 - remaining_bits)) - 1); Chris@16: val >>= 32 - remaining_bits; Chris@16: *begin++ = saved_bits | (extra_bits << remaining_bits); Chris@16: if(begin == end) return; Chris@16: available_bits -= 32 - remaining_bits; Chris@16: remaining_bits = 0; Chris@16: } Chris@16: if(bits >= 32) { Chris@16: for(; available_bits >= 32; available_bits -= 32) { Chris@16: boost::uint_least32_t word = boost::uint_least32_t(val) & 0xFFFFFFFFu; Chris@101: int suppress_warning = (bits >= 32); Chris@101: BOOST_ASSERT(suppress_warning == 1); Chris@101: val >>= (32 * suppress_warning); Chris@16: *begin++ = word; Chris@16: if(begin == end) return; Chris@16: } Chris@16: } Chris@16: remaining_bits = available_bits; Chris@16: saved_bits = static_cast(val); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void generate_impl(Engine& eng, Iter first, Iter last, boost::mpl::true_) Chris@16: { Chris@16: return detail::generate_from_int(eng, first, last); Chris@16: } Chris@16: Chris@16: template Chris@16: void generate_impl(Engine& eng, Iter first, Iter last, boost::mpl::false_) Chris@16: { Chris@16: return detail::generate_from_real(eng, first, last); Chris@16: } Chris@16: Chris@16: template Chris@16: void generate(Engine& eng, Iter first, Iter last) Chris@16: { Chris@16: return detail::generate_impl(eng, first, last, boost::is_integral()); Chris@16: } Chris@16: Chris@16: Chris@16: Chris@16: template Chris@16: IntType seed_one_int(SeedSeq& seq) Chris@16: { Chris@16: static const int log = ::boost::mpl::if_c<(m == 0), Chris@16: ::boost::mpl::int_<(::std::numeric_limits::digits)>, Chris@16: ::boost::static_log2 >::type::value; Chris@16: static const int k = Chris@16: (log + ((~(static_cast(2) << (log - 1)) & m)? 32 : 31)) / 32; Chris@16: ::boost::uint_least32_t array[log / 32 + 4]; Chris@16: seq.generate(&array[0], &array[0] + k + 3); Chris@16: IntType s = 0; Chris@16: for(int j = 0; j < k; ++j) { Chris@16: IntType digit = const_mod::apply(IntType(array[j+3])); Chris@16: IntType mult = IntType(1) << 32*j; Chris@16: s = const_mod::mult_add(mult, digit, s); Chris@16: } Chris@16: return s; Chris@16: } Chris@16: Chris@16: template Chris@16: IntType get_one_int(Iter& first, Iter last) Chris@16: { Chris@16: static const int log = ::boost::mpl::if_c<(m == 0), Chris@16: ::boost::mpl::int_<(::std::numeric_limits::digits)>, Chris@16: ::boost::static_log2 >::type::value; Chris@16: static const int k = Chris@16: (log + ((~(static_cast(2) << (log - 1)) & m)? 32 : 31)) / 32; Chris@16: IntType s = 0; Chris@16: for(int j = 0; j < k; ++j) { Chris@16: if(first == last) { Chris@101: boost::throw_exception(::std::invalid_argument("Not enough elements in call to seed.")); Chris@16: } Chris@16: IntType digit = const_mod::apply(IntType(*first++)); Chris@16: IntType mult = IntType(1) << 32*j; Chris@16: s = const_mod::mult_add(mult, digit, s); Chris@16: } Chris@16: return s; Chris@16: } Chris@16: Chris@16: // TODO: work in-place whenever possible Chris@16: template Chris@16: void seed_array_int_impl(SeedSeq& seq, UIntType (&x)[n]) Chris@16: { Chris@16: boost::uint_least32_t storage[((w+31)/32) * n]; Chris@16: seq.generate(&storage[0], &storage[0] + ((w+31)/32) * n); Chris@16: for(std::size_t j = 0; j < n; j++) { Chris@16: UIntType val = 0; Chris@16: for(std::size_t k = 0; k < (w+31)/32; ++k) { Chris@16: val += static_cast(storage[(w+31)/32*j + k]) << 32*k; Chris@16: } Chris@16: x[j] = val & ::boost::low_bits_mask_t::sig_bits; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::true_) Chris@16: { Chris@16: typedef typename boost::make_unsigned::type unsigned_array[n]; Chris@16: seed_array_int_impl(seq, reinterpret_cast(x)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void seed_array_int_impl(SeedSeq& seq, IntType (&x)[n], boost::mpl::false_) Chris@16: { Chris@16: seed_array_int_impl(seq, x); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void seed_array_int(SeedSeq& seq, IntType (&x)[n]) Chris@16: { Chris@16: seed_array_int_impl(seq, x, boost::is_signed()); Chris@16: } Chris@16: Chris@16: template Chris@16: void fill_array_int_impl(Iter& first, Iter last, UIntType (&x)[n]) Chris@16: { Chris@16: for(std::size_t j = 0; j < n; j++) { Chris@16: UIntType val = 0; Chris@16: for(std::size_t k = 0; k < (w+31)/32; ++k) { Chris@16: if(first == last) { Chris@101: boost::throw_exception(std::invalid_argument("Not enough elements in call to seed.")); Chris@16: } Chris@16: val += static_cast(*first++) << 32*k; Chris@16: } Chris@16: x[j] = val & ::boost::low_bits_mask_t::sig_bits; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost::mpl::true_) Chris@16: { Chris@16: typedef typename boost::make_unsigned::type unsigned_array[n]; Chris@16: fill_array_int_impl(first, last, reinterpret_cast(x)); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void fill_array_int_impl(Iter& first, Iter last, IntType (&x)[n], boost::mpl::false_) Chris@16: { Chris@16: fill_array_int_impl(first, last, x); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void fill_array_int(Iter& first, Iter last, IntType (&x)[n]) Chris@16: { Chris@16: fill_array_int_impl(first, last, x, boost::is_signed()); Chris@16: } Chris@16: Chris@16: template Chris@16: void seed_array_real_impl(const boost::uint_least32_t* storage, RealType (&x)[n]) Chris@16: { Chris@16: boost::uint_least32_t mask = ~((~boost::uint_least32_t(0)) << (w%32)); Chris@16: RealType two32 = 4294967296.0; Chris@16: const RealType divisor = RealType(1)/detail::pow2(w); Chris@16: unsigned int j; Chris@16: for(j = 0; j < n; ++j) { Chris@16: RealType val = RealType(0); Chris@16: RealType mult = divisor; Chris@16: for(int k = 0; k < w/32; ++k) { Chris@16: val += *storage++ * mult; Chris@16: mult *= two32; Chris@16: } Chris@16: if(mask != 0) { Chris@16: val += (*storage++ & mask) * mult; Chris@16: } Chris@16: BOOST_ASSERT(val >= 0); Chris@16: BOOST_ASSERT(val < 1); Chris@16: x[j] = val; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void seed_array_real(SeedSeq& seq, RealType (&x)[n]) Chris@16: { Chris@16: using std::pow; Chris@16: boost::uint_least32_t storage[((w+31)/32) * n]; Chris@16: seq.generate(&storage[0], &storage[0] + ((w+31)/32) * n); Chris@16: seed_array_real_impl(storage, x); Chris@16: } Chris@16: Chris@16: template Chris@16: void fill_array_real(Iter& first, Iter last, RealType (&x)[n]) Chris@16: { Chris@16: boost::uint_least32_t mask = ~((~boost::uint_least32_t(0)) << (w%32)); Chris@16: RealType two32 = 4294967296.0; Chris@16: const RealType divisor = RealType(1)/detail::pow2(w); Chris@16: unsigned int j; Chris@16: for(j = 0; j < n; ++j) { Chris@16: RealType val = RealType(0); Chris@16: RealType mult = divisor; Chris@16: for(int k = 0; k < w/32; ++k, ++first) { Chris@101: if(first == last) boost::throw_exception(std::invalid_argument("Not enough elements in call to seed.")); Chris@16: val += *first * mult; Chris@16: mult *= two32; Chris@16: } Chris@16: if(mask != 0) { Chris@101: if(first == last) boost::throw_exception(std::invalid_argument("Not enough elements in call to seed.")); Chris@16: val += (*first & mask) * mult; Chris@16: ++first; Chris@16: } Chris@16: BOOST_ASSERT(val >= 0); Chris@16: BOOST_ASSERT(val < 1); Chris@16: x[j] = val; Chris@16: } Chris@16: } Chris@16: Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: #include Chris@16: Chris@16: #endif