|
1409 | 1409 | template<class Engine, size_t k>
|
1410 | 1410 | class shuffle_order_engine;
|
1411 | 1411 |
|
| 1412 | + // \ref{rand.eng.philox}, class template \tcode{philox_engine} |
| 1413 | + template<class UIntType, size_t w, size_t n, size_t r, UIntType... consts> |
| 1414 | + class philox_engine; |
| 1415 | + |
1412 | 1416 | // \ref{rand.predef}, engines and engine adaptors with predefined parameters
|
1413 | 1417 | using minstd_rand0 = @\seebelow@;
|
1414 | 1418 | using minstd_rand = @\seebelow@;
|
|
1419 | 1423 | using ranlux24 = @\seebelow@;
|
1420 | 1424 | using ranlux48 = @\seebelow@;
|
1421 | 1425 | using knuth_b = @\seebelow@;
|
| 1426 | + using philox4x32 = @\seebelow@; |
| 1427 | + using philox4x64 = @\seebelow@; |
1422 | 1428 |
|
1423 | 1429 | using default_random_engine = @\seebelow@;
|
1424 | 1430 |
|
|
3061 | 3067 | otherwise sets $c$ to $0$.
|
3062 | 3068 | \end{itemdescr}
|
3063 | 3069 |
|
| 3070 | +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
| 3071 | +% philox_engine engine: |
| 3072 | + |
| 3073 | +\rSec3[rand.eng.philox]{Class template \tcode{philox_engine}}% |
| 3074 | +\indexlibraryglobal{philox_engine}% |
| 3075 | + |
| 3076 | +\pnum |
| 3077 | +A \tcode{philox_engine} random number engine produces |
| 3078 | +unsigned integer random numbers in the closed interval \crange{0}{$m$}, |
| 3079 | +where $m = 2^w - 1$ and |
| 3080 | +the template parameter $w$ defines the range of the produced numbers. |
| 3081 | +The state of a \tcode{philox_engine} object consists of |
| 3082 | +a sequence $X$ of $n$ unsigned integer values of width $w$, |
| 3083 | +a sequence $K$ of $n/2$ values of \tcode{result_type}, |
| 3084 | +a sequence $Y$ of $n$ values of \tcode{result_type}, and |
| 3085 | +a scalar $i$, where |
| 3086 | +\begin{itemize} |
| 3087 | +\item |
| 3088 | +$X$ is the interpretation of the unsigned integer \term{counter} value |
| 3089 | +$Z \cedef \sum_{j = 0}^{n - 1} X_j \cdot 2^{wj}$ of $n \cdot w$ bits, |
| 3090 | +\item |
| 3091 | +$K$ are keys, which are generated once from the seed (see constructors below) |
| 3092 | +and remain constant unless the \tcode{seed} function\iref{rand.req.eng} is invoked, |
| 3093 | +\item |
| 3094 | +$Y$ stores a batch of output values, and |
| 3095 | +\item |
| 3096 | +$i$ is an index for an element of the sequence $Y$. |
| 3097 | +\end{itemize} |
| 3098 | + |
| 3099 | +\pnum |
| 3100 | +The generation algorithm returns $Y_i$, |
| 3101 | +the value stored in the $i^{th}$ element of $Y$ after applying |
| 3102 | +the transition algorithm. |
| 3103 | + |
| 3104 | +\pnum |
| 3105 | +The state transition is performed as if by the following algorithm: |
| 3106 | +\begin{codeblock} |
| 3107 | +@$i$@ = @$i$@ + 1 |
| 3108 | +if (@$i$@ == @$n$@) { |
| 3109 | + @$Y$@ = Philox(@$K$@, @$X$@) // \seebelow |
| 3110 | + @$Z$@ = @$Z$@ + 1 |
| 3111 | + @$i$@ = 0 |
| 3112 | +} |
| 3113 | +\end{codeblock} |
| 3114 | + |
| 3115 | +\pnum |
| 3116 | +The \tcode{Philox} function maps the length-$n/2$ sequence $K$ and |
| 3117 | +the length-$n$ sequence $X$ into a length-$n$ output sequence $Y$. |
| 3118 | +Philox applies an $r$-round substitution-permutation network to the values in $X$. |
| 3119 | +A single round of the generation algorithm performs the following steps: |
| 3120 | +\begin{itemize} |
| 3121 | +\item |
| 3122 | +The output sequence $X'$ of the previous round |
| 3123 | +($X$ in case of the first round) |
| 3124 | +is permuted to obtain the intermediate state $V$: |
| 3125 | +\begin{codeblock} |
| 3126 | +@$V_j = X'_{f_n(j)}$@ |
| 3127 | +\end{codeblock} |
| 3128 | +where $j = 0, \dotsc, n - 1$ and |
| 3129 | +$f_n(j)$ is defined in \tref{rand.eng.philox.f}. |
| 3130 | + |
| 3131 | +\begin{floattable}{Values for the word permutation $\bm{f}_{\bm{n}}\bm{(j)}$}{rand.eng.philox.f} |
| 3132 | +{l|l|l|l|l|l|l|l|l|l|l|l|l|l|l|l|l|l} |
| 3133 | +\topline |
| 3134 | + \multicolumn{2}{|c|}{$\bm{f}_{\bm{n}}\bm{(j)}$} & \multicolumn{16}{c|}{$\bm{j}$} \\ \cline{3-18} |
| 3135 | + \multicolumn{2}{|c|}{} |
| 3136 | + & 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 11 & 12 & 13 & 14 & 15 \\ \hline |
| 3137 | + $\bm{n} $ & 2 & 0 & 1 & \multicolumn{14}{c|}{} \\ \cline{2-18} |
| 3138 | + & 4 & 0 & 3 & 2 & 1 & \multicolumn{12}{c|}{} \\ \cline{2-18} |
| 3139 | + & 8 & 2 & 1 & 4 & 7 & 6 & 5 & 0 & 3 & \multicolumn{8}{c|}{} \\ \cline{2-18} |
| 3140 | + & 16 & 0 & 9 & 2 & 13 & 6 & 11 & 4 & 15 & 10 & 7 & 12 & 3 & 14 & 5 & 8 & 1 \\ \cline{2-18} |
| 3141 | +\end{floattable} |
| 3142 | +\begin{note} |
| 3143 | +For $n = 2$ the sequence is not permuted. |
| 3144 | +\end{note} |
| 3145 | + |
| 3146 | +\item |
| 3147 | +The following computations are applied to the elements of the $V$ sequence: |
| 3148 | +\begin{codeblock} |
| 3149 | +@$X_{2k + 0} = \mullo(V_{2k + 1}, M_{k}, w)$@ |
| 3150 | +@$X_{2k + 1} = \mulhi(V_{2k + 1}, M_{k}, w) \xor \mathit{key}^q_k \xor V_{2k}$@ |
| 3151 | +\end{codeblock} |
| 3152 | +where: |
| 3153 | + \begin{itemize} |
| 3154 | + \item |
| 3155 | + $\mullo(\tcode{a}, \tcode{b}, \tcode{w})$ is |
| 3156 | + the low half of the modular multiplication of \tcode{a} and \tcode{b}: |
| 3157 | + $(\tcode{a} \cdot \tcode{b}) \mod 2^w$, |
| 3158 | + |
| 3159 | + \item |
| 3160 | + $\mulhi(\tcode{a}, \tcode{b}, \tcode{w})$ is |
| 3161 | + the high half of the modular multiplication of \tcode{a} and \tcode{b}: |
| 3162 | + $(\left\lfloor (\tcode{a} \cdot \tcode{b}) / 2^w \right\rfloor)$, |
| 3163 | + |
| 3164 | + \item |
| 3165 | + $k = 0, \dotsc, n/2 - 1$ is the index in the sequences, |
| 3166 | + |
| 3167 | + \item |
| 3168 | + $q = 0, \dotsc, r - 1$ is the index of the round, |
| 3169 | + |
| 3170 | + \item |
| 3171 | + $\mathit{key}^q_k$ is the $k^\text{th}$ round key for round $q$, |
| 3172 | + $\mathit{key}^q_k \cedef (K_k + q \cdot C_k) \mod 2^w$, |
| 3173 | + |
| 3174 | + \item |
| 3175 | + $K_k$ are the elements of the key sequence $K$, |
| 3176 | + |
| 3177 | + \item |
| 3178 | + $M_k$ is \tcode{multipliers[$k$]}, and |
| 3179 | + |
| 3180 | + \item |
| 3181 | + $C_k$ is \tcode{round_consts[$k$]}. |
| 3182 | + \end{itemize} |
| 3183 | +\end{itemize} |
| 3184 | + |
| 3185 | +\pnum |
| 3186 | +After $r$ applications of the single-round function, |
| 3187 | +\tcode{Philox} returns the sequence $Y = X'$. |
| 3188 | + |
| 3189 | +\indexlibraryglobal{philox_engine}% |
| 3190 | +\indexlibrarymember{result_type}{philox_engine}% |
| 3191 | +\begin{codeblock} |
| 3192 | +namespace std { |
| 3193 | + template<class UIntType, size_t w, size_t n, size_t r, UIntType... consts> |
| 3194 | + class philox_engine { |
| 3195 | + static constexpr size_t @\exposid{array-size}@ = n / 2; // \expos |
| 3196 | + public: |
| 3197 | + // types |
| 3198 | + using result_type = UIntType; |
| 3199 | + |
| 3200 | + // engine characteristics |
| 3201 | + static constexpr size_t word_size = w; |
| 3202 | + static constexpr size_t word_count = n; |
| 3203 | + static constexpr size_t round_count = r; |
| 3204 | + static constexpr array<result_type, @\exposid{array-size}@> multipliers; |
| 3205 | + static constexpr array<result_type, @\exposid{array-size>}@ round_consts; |
| 3206 | + static constexpr result_type min() { return 0; } |
| 3207 | + static constexpr result_type max() { return m - 1; } |
| 3208 | + static constexpr result_type default_seed = 20111115u; |
| 3209 | + |
| 3210 | + // constructors and seeding functions |
| 3211 | + philox_engine() : philox_engine(default_seed) {} |
| 3212 | + explicit philox_engine(result_type value); |
| 3213 | + template<class Sseq> explicit philox_engine(Sseq& q); |
| 3214 | + void seed(result_type value = default_seed); |
| 3215 | + template<class Sseq> void seed(Sseq& q); |
| 3216 | + |
| 3217 | + void set_counter(const array<result_type, n>& counter); |
| 3218 | + |
| 3219 | + // equality operators |
| 3220 | + friend bool operator==(const philox_engine& x, const philox_engine& y); |
| 3221 | + |
| 3222 | + // generating functions |
| 3223 | + result_type operator()(); |
| 3224 | + void discard(unsigned long long z); |
| 3225 | + |
| 3226 | + // inserters and extractors |
| 3227 | + template<class charT, class traits> |
| 3228 | + friend basic_ostream<charT, traits>& |
| 3229 | + operator<<(basic_ostream<charT, traits>& os, const philox_engine& x); |
| 3230 | + template<class charT, class traits> |
| 3231 | + friend basic_istream<charT, traits>& |
| 3232 | + operator>>(basic_istream<charT, traits>& is, philox_engine& x); |
| 3233 | + }; |
| 3234 | +} |
| 3235 | +\end{codeblock} |
| 3236 | + |
| 3237 | +\pnum |
| 3238 | +\mandates |
| 3239 | +\begin{itemize} |
| 3240 | +\item \tcode{sizeof...(consts) == n} is \tcode{true}, and |
| 3241 | +\item \tcode{n == 2 || n == 4 || n == 8 || n == 16} is \tcode{true}, and |
| 3242 | +\item \tcode{0 < r} is \tcode{true}, and |
| 3243 | +\item \tcode{0 < w \&\& w <= numeric_limits<UIntType>::digits} is \tcode{true}. |
| 3244 | +\end{itemize} |
| 3245 | + |
| 3246 | +\pnum |
| 3247 | +The template parameter pack \tcode{consts} represents |
| 3248 | +the $M_k$ and $C_k$ constants which are grouped as follows: |
| 3249 | +$[ M_0, C_0, M_1, C_1, M_2, C_2, \dotsc, M_{n/2 - 1}, C_{n/2 - 1} ]$. |
| 3250 | + |
| 3251 | +\pnum |
| 3252 | +The textual representation consists of the values of |
| 3253 | +$K_0, \dotsc, K_{n/2 - 1}, X_{0}, \dotsc, X_{n - 1}, i$, in that order. |
| 3254 | +\begin{note} |
| 3255 | +The stream extraction operator can reconstruct $Y$ from $K$ and $X$, as needed. |
| 3256 | +\end{note} |
| 3257 | + |
| 3258 | +\indexlibraryctor{philox_engine} |
| 3259 | +\begin{itemdecl} |
| 3260 | +explicit philox_engine(result_type value); |
| 3261 | +\end{itemdecl} |
| 3262 | + |
| 3263 | +\begin{itemdescr} |
| 3264 | +\pnum |
| 3265 | +\effects |
| 3266 | +Sets the $K_0$ element of sequence $K$ to $\tcode{value} \mod 2^w$. |
| 3267 | +All elements of sequences $X$ and $K$ (except $K_0$) are set to \tcode{0}. |
| 3268 | +The value of $i$ is set to $n - 1$. |
| 3269 | +\end{itemdescr} |
| 3270 | + |
| 3271 | +\indexlibraryctor{philox_engine} |
| 3272 | +\begin{itemdecl} |
| 3273 | +template<class Sseq> explicit philox_engine(Sseq& q); |
| 3274 | +\end{itemdecl} |
| 3275 | + |
| 3276 | +\begin{itemdescr} |
| 3277 | +\pnum |
| 3278 | +\effects |
| 3279 | +With $p = \left\lceil w / 32 \right\rceil$ and |
| 3280 | +an array (or equivalent) \tcode{a} of length $(n/2) \cdot p$, |
| 3281 | +invokes \tcode{q.generate(a + 0, a + n / 2 * $p$)} and |
| 3282 | +then iteratively for $k = 0, \dotsc, n/2 - 1$, |
| 3283 | +sets $K_k$ to |
| 3284 | +$\left(\sum_{j = 0}^{p - 1} a_{k p + j} \cdot 2^{32j} \right) \mod 2^w$. |
| 3285 | +All elements of sequence $X$ are set to \tcode{0}. |
| 3286 | +The value of $i$ is set to $n - 1$. |
| 3287 | +\end{itemdescr} |
| 3288 | + |
| 3289 | +\indexlibrarymember{set_counter}{philox_engine}% |
| 3290 | +\begin{itemdecl} |
| 3291 | +void set_counter(const array<result_type, n>& c); |
| 3292 | +\end{itemdecl} |
| 3293 | + |
| 3294 | +\begin{itemdescr} |
| 3295 | +\pnum |
| 3296 | +\effects |
| 3297 | +For $j = 0, \dotsc, n - 1$ sets $X_j$ to $C_{n - 1 - j} \mod 2^w$. |
| 3298 | +The value of $i$ is set to $n - 1$. |
| 3299 | +\begin{note} |
| 3300 | +The counter is the value $Z$ introduced at the beginning of this subclause. |
| 3301 | +\end{note} |
| 3302 | +\end{itemdescr} |
3064 | 3303 |
|
3065 | 3304 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
3066 | 3305 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
3662 | 3901 | need not generate identical sequences across implementations.
|
3663 | 3902 | \end{note}
|
3664 | 3903 | \end{itemdescr}%
|
| 3904 | + |
| 3905 | +\indexlibraryglobal{philox4x32}% |
| 3906 | +\begin{itemdecl} |
| 3907 | +using philox4x32 = |
| 3908 | + philox_engine<uint_fast32_t, 32, 4, 10, |
| 3909 | + 0xD2511F53, 0x9E3779B9, 0xCD9E8D57, 0xBB67AE85>; |
| 3910 | +\end{itemdecl} |
| 3911 | + |
| 3912 | +\begin{itemdescr} |
| 3913 | +\pnum |
| 3914 | +\required |
| 3915 | +The $10000^\text{th}$ consecutive invocation |
| 3916 | +a default-constructed object of type \tcode{philox4x32} |
| 3917 | +produces the value $1955073260$. |
| 3918 | +\end{itemdescr}% |
| 3919 | + |
| 3920 | +\indexlibraryglobal{philox4x64}% |
| 3921 | +\begin{itemdecl} |
| 3922 | +using philox4x64 = |
| 3923 | + philox_engine<uint_fast64_t, 64, 4, 10, |
| 3924 | + 0xD2E7470EE14C6C93, 0x9E3779B97F4A7C15, 0xCA5A826395121157, 0xBB67AE8584CAA73B>; |
| 3925 | +\end{itemdecl} |
| 3926 | + |
| 3927 | +\begin{itemdescr} |
| 3928 | +\pnum |
| 3929 | +\required |
| 3930 | +The $10000^\text{th}$ consecutive invocation |
| 3931 | +a default-constructed object of type \tcode{philox4x64} |
| 3932 | +produces the value $3409172418970261260$. |
| 3933 | +\end{itemdescr}% |
3665 | 3934 | \indextext{random number generation!predefined engines and adaptors|)}%
|
3666 | 3935 | \indextext{random number engine adaptor!with predefined parameters|)}%
|
3667 | 3936 | \indextext{random number engine!with predefined parameters|)}
|
|
0 commit comments