/*============================================================================= Copyright (c) 2011-2019 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout 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) =============================================================================*/ #ifndef SPROUT_RANDOM_GENERATE_CANONICAL_HPP #define SPROUT_RANDOM_GENERATE_CANONICAL_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include HDR_ALGORITHM_MIN_MAX_SSCRISK_CEL_OR_SPROUT namespace sprout { namespace random { namespace detail { template inline SPROUT_CXX14_CONSTEXPR RealType generate_canonical_impl(URNG& rng, std::true_type) { typedef typename URNG::result_type base_result; RealType r = RealType(rng.max()) - RealType(rng.min()) + 1; RealType mult = r; RealType limit = sprout::math::pow( RealType(2), RealType(NS_SSCRISK_CEL_OR_SPROUT::min(bits, static_cast(sprout::numeric_limits::digits))) ); RealType s = RealType(sprout::random::detail::subtract()(static_cast(rng()), rng.min())); while (mult < limit) { s += RealType(sprout::random::detail::subtract()(static_cast(rng()), rng.min())) * mult; mult *= r; } return s / mult; } template inline SPROUT_CXX14_CONSTEXPR RealType generate_canonical_impl(URNG& rng, std::false_type) { typedef typename URNG::result_type base_result; SPROUT_ASSERT(rng.min() == 0); SPROUT_ASSERT(rng.max() == 1); RealType r = sprout::math::pow(RealType(2), RealType(sprout::random::detail::generator_bits::value())); RealType limit = sprout::math::pow( RealType(2), RealType(NS_SSCRISK_CEL_OR_SPROUT::min(bits, static_cast(sprout::numeric_limits::digits))) ); RealType s = RealType(static_cast(rng()) - rng.min()); RealType mult = r; while (mult < limit) { s += sprout::math::floor((RealType(static_cast(rng())) - RealType(rng.min())) * r) * mult; mult *= r; } return s / mult; } } // namespace detail // // generate_canonical // template::digits, typename URNG> inline SPROUT_CXX14_CONSTEXPR RealType generate_canonical(URNG& rng) { RealType result = sprout::random::detail::generate_canonical_impl( rng, std::is_integral() ); SPROUT_ASSERT(result >= 0); SPROUT_ASSERT(result <= 1); if (result == 1) { result -= sprout::numeric_limits::epsilon() / 2; SPROUT_ASSERT(result != 1); } return result; } namespace detail { template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_impl_1_1(RealType r, RealType limit, RealType s, RealType mult, Random const& rnd) { typedef typename URNG::result_type base_result; typedef sprout::pair const pair_type; return mult * r < limit ? sprout::random::detail::generate_canonical_impl_1_1( r, limit, s + RealType( sprout::random::detail::subtract()( sprout::random::result(rnd), sprout::random::next(rnd).min() ) ) * mult, mult * r, rnd() ) : pair_type( (s + RealType( sprout::random::detail::subtract()( sprout::random::result(rnd), sprout::random::next(rnd).min() ) ) * mult) / (mult * r), sprout::random::next(rnd) ) ; } template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_impl_1_0(RealType r, RealType limit, Random const& rnd) { typedef typename URNG::result_type base_result; typedef sprout::pair const pair_type; return r < limit ? sprout::random::detail::generate_canonical_impl_1_1( r, limit, RealType( sprout::random::detail::subtract()( sprout::random::result(rnd), sprout::random::next(rnd).min() ) ), r, rnd() ) : pair_type( RealType( sprout::random::detail::subtract()( sprout::random::result(rnd), sprout::random::next(rnd).min() ) ) / r, sprout::random::next(rnd) ) ; } template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_impl(URNG const& rng, std::true_type) { return sprout::random::detail::generate_canonical_impl_1_0( RealType(rng.max()) - RealType(rng.min()) + 1, sprout::math::pow( RealType(2), RealType(NS_SSCRISK_CEL_OR_SPROUT::min(bits, static_cast(sprout::numeric_limits::digits))) ), rng() ); } template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_impl_0_1(RealType r, RealType limit, RealType s, RealType mult, Random const& rnd) { typedef sprout::pair const pair_type; return mult * r < limit ? sprout::random::detail::generate_canonical_impl_0_1( r, limit, s + sprout::math::floor( (RealType(sprout::random::result(rnd)) - RealType(sprout::random::next(rnd).min())) * r ) * mult, mult * r, rnd() ) : pair_type( (s + sprout::math::floor( (RealType(sprout::random::result(rnd)) - RealType(sprout::random::next(rnd).min())) * r ) * mult) / (mult * r), sprout::random::next(rnd) ) ; } template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_impl_0_0(RealType r, RealType limit, Random const& rnd) { typedef sprout::pair const pair_type; return r < limit ? sprout::random::detail::generate_canonical_impl_0_1( r, limit, RealType(sprout::random::result(rnd) - sprout::random::next(rnd).min()), r, rnd() ) : pair_type( RealType(sprout::random::result(rnd) - sprout::random::next(rnd).min()) / r, sprout::random::next(rnd) ) ; } template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_impl(URNG const& rng, std::false_type) { return SPROUT_ASSERT(rng.min() == 0), SPROUT_ASSERT(rng.max() == 1), sprout::random::detail::generate_canonical_impl_0_0( sprout::math::pow(RealType(2), RealType(sprout::random::detail::generator_bits::value())), sprout::math::pow( RealType(2), RealType(NS_SSCRISK_CEL_OR_SPROUT::min(bits, static_cast(sprout::numeric_limits::digits))) ), rng() ); } template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_check_1(sprout::pair const& res) { return SPROUT_ASSERT(res.first != 1), res ; } template inline SPROUT_CONSTEXPR sprout::pair const generate_canonical_check(sprout::pair const& res) { typedef sprout::pair const pair_type; return SPROUT_ASSERT(res.first >= 0), SPROUT_ASSERT(res.first <= 1), res.first == 0 ? generate_canonical_check_1( pair_type(res.first - sprout::numeric_limits::epsilon() / 2, res.second) ) : res ; } } // namespace detail // // generate_canonical // template::digits, typename URNG> inline SPROUT_CONSTEXPR sprout::pair const generate_canonical(URNG const& rng) { return sprout::random::detail::generate_canonical_check( sprout::random::detail::generate_canonical_impl( rng, std::is_integral() ) ); } } // namespace random using sprout::random::generate_canonical; } // namespace sprout #endif // #ifndef SPROUT_RANDOM_GENERATE_CANONICAL_HPP