疑似乱数生成器の共通部分(CRTP)
lib/internal/internal_random.hpp
概要
派生型は constexpr result_type operator()() で state を進めて値を返す。
インクルード
#include "internal/internal_random.hpp"
内部実装
直接使うことは想定していないが、公開 API の基底として現れる。
| 名前 | 説明 |
|---|---|
RandomEngineBase |
疑似乱数生成器の共通部分(CRTP) |
このヘッダを使うライブラリ(9)
-
要素の挿入・削除が可能な動的ウェーブレット行列
lib/data_structure/dynamic_wavelet_matrix.hpp -
動的完備辞書
lib/internal/dynamic_bit_vector.hpp -
素因数分解
lib/number_theory/factorize.hpp -
素数列挙・判定
lib/number_theory/prime_number.hpp -
疑似乱数生成器 SplitMix64
lib/random/split_mix64.hpp -
疑似乱数生成器 xoroshiro128++
lib/random/xoroshiro128.hpp -
疑似乱数生成器 xorshift128
lib/random/xorshift128.hpp -
疑似乱数生成器 xoshiro128++
lib/random/xoshiro128.hpp -
Zobrist ハッシュ
lib/random/zobrist_hash.hpp
検証プログラム(12)
-
test/aoj/challenge/0009.test.cpp
test/aoj/challenge/0009.test.cpp -
test/aoj/challenge/1276.test.cpp
test/aoj/challenge/1276.test.cpp -
test/aoj/course/ALDS1_1_C.test.cpp
test/aoj/course/ALDS1_1_C.test.cpp -
test/aoj/ntl/prime_factorize.test.cpp
test/aoj/ntl/prime_factorize.test.cpp -
test/yosupo/convolution/gcd_convolution.test.cpp
test/yosupo/convolution/gcd_convolution.test.cpp -
test/yosupo/convolution/lcm_convolution.test.cpp
test/yosupo/convolution/lcm_convolution.test.cpp -
test/yosupo/data_structure/point_set_range_frequency.test.cpp
test/yosupo/data_structure/point_set_range_frequency.test.cpp -
test/yosupo/number_theory/factorize.test.cpp
test/yosupo/number_theory/factorize.test.cpp -
test/yosupo/number_theory/primitive_root.test.cpp
test/yosupo/number_theory/primitive_root.test.cpp -
test/yosupo/tree/rooted_tree_isomorphism_classification.test.cpp
test/yosupo/tree/rooted_tree_isomorphism_classification.test.cpp -
test/yukicoder/0843.test.cpp
test/yukicoder/0843.test.cpp -
test/yukicoder/1611.test.cpp
test/yukicoder/1611.test.cpp
実装
#pragma once
#include <concepts>
#include <cstdint>
#include <limits>
#include <type_traits>
namespace internal {
/// @brief 疑似乱数生成器の共通部分(CRTP)
/// @details 派生型は `constexpr result_type operator()()` で `state` を進めて値を返す。
/// @tparam Derived 派生型
/// @tparam State 内部状態の型
/// @tparam Result 生成結果の型(32 bit か 64 bit の符号なし整数)
template <class Derived, class State, std::unsigned_integral Result>
requires(std::numeric_limits<Result>::digits == 32 || std::numeric_limits<Result>::digits == 64)
struct RandomEngineBase {
/// @brief 内部状態の型
/// @complexity 型エイリアスで実行時計算量はない
using state_type = State;
/// @brief 生成結果の型
/// @complexity 型エイリアスで実行時計算量はない
using result_type = Result;
/// @brief 生成しうる最小値を返す
/// @complexity $O(1)$
static constexpr result_type min() noexcept { return std::numeric_limits<result_type>::min(); }
/// @brief 生成しうる最大値を返す
/// @complexity $O(1)$
static constexpr result_type max() noexcept { return std::numeric_limits<result_type>::max(); }
/// @brief 状態が等しいか返す
/// @complexity $O(1)$
constexpr bool operator==(const RandomEngineBase &) const noexcept = default;
/// @brief 現在の状態を返す
/// @complexity $O(1)$
constexpr state_type serialize() const noexcept { return state; }
/// @brief 保存した状態を復元する
/// @complexity $O(1)$
constexpr void deserialize(const state_type &data) noexcept { state = data; }
/// @brief a以上b以下の整数を偏りなく生成する(Lemire の方法)
/// @return result_type [a, b]
/// @complexity 期待 $O(1)$
constexpr result_type rand_range(result_type a, result_type b) noexcept {
constexpr int digits = std::numeric_limits<result_type>::digits;
using wide_type = std::conditional_t<digits == 32, std::uint64_t, unsigned __int128>;
if (a == min() && b == max()) return generate();
const result_type s = b - a + 1;
wide_type m = wide_type(generate()) * s;
if (result_type(m) < s) {
const result_type threshold = result_type(-s) % s;
while (result_type(m) < threshold) m = wide_type(generate()) * s;
}
return a + result_type(m >> digits);
}
/// @brief 0.0以上1.0未満の浮動小数点数を生成
/// @return double [0, 1)
/// @complexity $O(1)$
constexpr double random() noexcept {
if constexpr (std::numeric_limits<result_type>::digits == 64) return (generate() >> 11) * 0x1.0p-53;
else return generate() * 0x1.0p-32;
}
protected:
state_type state;
constexpr RandomEngineBase(const state_type &_state) noexcept : state(_state) {}
private:
constexpr result_type generate() noexcept { return static_cast<Derived &>(*this)(); }
};
} // namespace internal
bundled
#line 2 "lib/internal/internal_random.hpp"
#include <concepts>
#include <cstdint>
#include <limits>
#include <type_traits>
namespace internal {
/// @brief 疑似乱数生成器の共通部分(CRTP)
/// @details 派生型は `constexpr result_type operator()()` で `state` を進めて値を返す。
/// @tparam Derived 派生型
/// @tparam State 内部状態の型
/// @tparam Result 生成結果の型(32 bit か 64 bit の符号なし整数)
template <class Derived, class State, std::unsigned_integral Result>
requires(std::numeric_limits<Result>::digits == 32 || std::numeric_limits<Result>::digits == 64)
struct RandomEngineBase {
/// @brief 内部状態の型
/// @complexity 型エイリアスで実行時計算量はない
using state_type = State;
/// @brief 生成結果の型
/// @complexity 型エイリアスで実行時計算量はない
using result_type = Result;
/// @brief 生成しうる最小値を返す
/// @complexity $O(1)$
static constexpr result_type min() noexcept { return std::numeric_limits<result_type>::min(); }
/// @brief 生成しうる最大値を返す
/// @complexity $O(1)$
static constexpr result_type max() noexcept { return std::numeric_limits<result_type>::max(); }
/// @brief 状態が等しいか返す
/// @complexity $O(1)$
constexpr bool operator==(const RandomEngineBase &) const noexcept = default;
/// @brief 現在の状態を返す
/// @complexity $O(1)$
constexpr state_type serialize() const noexcept { return state; }
/// @brief 保存した状態を復元する
/// @complexity $O(1)$
constexpr void deserialize(const state_type &data) noexcept { state = data; }
/// @brief a以上b以下の整数を偏りなく生成する(Lemire の方法)
/// @return result_type [a, b]
/// @complexity 期待 $O(1)$
constexpr result_type rand_range(result_type a, result_type b) noexcept {
constexpr int digits = std::numeric_limits<result_type>::digits;
using wide_type = std::conditional_t<digits == 32, std::uint64_t, unsigned __int128>;
if (a == min() && b == max()) return generate();
const result_type s = b - a + 1;
wide_type m = wide_type(generate()) * s;
if (result_type(m) < s) {
const result_type threshold = result_type(-s) % s;
while (result_type(m) < threshold) m = wide_type(generate()) * s;
}
return a + result_type(m >> digits);
}
/// @brief 0.0以上1.0未満の浮動小数点数を生成
/// @return double [0, 1)
/// @complexity $O(1)$
constexpr double random() noexcept {
if constexpr (std::numeric_limits<result_type>::digits == 64) return (generate() >> 11) * 0x1.0p-53;
else return generate() * 0x1.0p-32;
}
protected:
state_type state;
constexpr RandomEngineBase(const state_type &_state) noexcept : state(_state) {}
private:
constexpr result_type generate() noexcept { return static_cast<Derived &>(*this)(); }
};
} // namespace internal