random123

Counter-based Random Number Generators
git clone git://git.meso-star.com/random123.git
Log | Files | Refs | README | LICENSE

philox.h (22028B)


      1 /*
      2 Copyright 2010-2011, D. E. Shaw Research.
      3 All rights reserved.
      4 
      5 Redistribution and use in source and binary forms, with or without
      6 modification, are permitted provided that the following conditions are
      7 met:
      8 
      9 * Redistributions of source code must retain the above copyright
     10   notice, this list of conditions, and the following disclaimer.
     11 
     12 * Redistributions in binary form must reproduce the above copyright
     13   notice, this list of conditions, and the following disclaimer in the
     14   documentation and/or other materials provided with the distribution.
     15 
     16 * Neither the name of D. E. Shaw Research nor the names of its
     17   contributors may be used to endorse or promote products derived from
     18   this software without specific prior written permission.
     19 
     20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 */
     32 #ifndef _philox_dot_h_
     33 #define _philox_dot_h_
     34 
     35 /** \cond HIDDEN_FROM_DOXYGEN */
     36 
     37 #include "features/compilerfeatures.h"
     38 #include "array.h"
     39 
     40 
     41 /*
     42 // Macros _Foo_tpl are code generation 'templates'  They define
     43 // inline functions with names obtained by mangling Foo and the
     44 // macro arguments.  E.g.,
     45 //   _mulhilo_tpl(32, uint32_t, uint64_t)
     46 // expands to a definition of:
     47 //   mulhilo32(uint32_t, uint32_t, uint32_t *, uint32_t *)
     48 // We then 'instantiate the template' to define
     49 // several different functions, e.g.,
     50 //   mulhilo32
     51 //   mulhilo64
     52 // These functions will be visible to user code, and may
     53 // also be used later in subsequent templates and definitions.
     54 
     55 // A template for mulhilo using a temporary of twice the word-width.
     56 // Gcc figures out that this can be reduced to a single 'mul' instruction,
     57 // despite the apparent use of double-wide variables, shifts, etc.  It's
     58 // obviously not guaranteed that all compilers will be that smart, so
     59 // other implementations might be preferable, e.g., using an intrinsic
     60 // or an asm block.  On the other hand, for 32-bit multiplies,
     61 // this *is* perfectly standard C99 - any C99 compiler should 
     62 // understand it and produce correct code.  For 64-bit multiplies,
     63 // it's only usable if the compiler recognizes that it can do
     64 // arithmetic on a 128-bit type.  That happens to be true for gcc on
     65 // x86-64, and powerpc64 but not much else.
     66 */
     67 #define _mulhilo_dword_tpl(W, Word, Dword)                              \
     68 R123_CUDA_DEVICE R123_STATIC_INLINE Word mulhilo##W(Word a, Word b, Word* hip){ \
     69     Dword product = ((Dword)a)*((Dword)b);                              \
     70     *hip = product>>W;                                                  \
     71     return (Word)product;                                               \
     72 }
     73 
     74 /*
     75 // A template for mulhilo using gnu-style asm syntax.
     76 // INSN can be "mulw", "mull" or "mulq".  
     77 // FIXME - porting to other architectures, we'll need still-more conditional
     78 // branching here.  Note that intrinsics are usually preferable.
     79 */
     80 #ifdef __powerpc__
     81 #define _mulhilo_asm_tpl(W, Word, INSN)                         \
     82 R123_STATIC_INLINE Word mulhilo##W(Word ax, Word b, Word *hip){ \
     83     Word dx = 0;                                                \
     84     __asm__("\n\t"                                              \
     85         INSN " %0,%1,%2\n\t"                                    \
     86         : "=r"(dx)                                              \
     87         : "r"(b), "r"(ax)                                       \
     88         );                                                      \
     89     *hip = dx;                                                  \
     90     return ax*b;                                                \
     91 }
     92 #else
     93 #define _mulhilo_asm_tpl(W, Word, INSN)                         \
     94 R123_STATIC_INLINE Word mulhilo##W(Word ax, Word b, Word *hip){      \
     95     Word dx;                                                    \
     96     __asm__("\n\t"                                              \
     97         INSN " %2\n\t"                                          \
     98         : "=a"(ax), "=d"(dx)                                    \
     99         : "r"(b), "0"(ax)                                       \
    100         );                                                      \
    101     *hip = dx;                                                  \
    102     return ax;                                                  \
    103 }
    104 #endif /* __powerpc__ */
    105 
    106 /*
    107 // A template for mulhilo using MSVC-style intrinsics
    108 // For example,_umul128 is an msvc intrinsic, c.f.
    109 // http://msdn.microsoft.com/en-us/library/3dayytw9.aspx
    110 */
    111 #define _mulhilo_msvc_intrin_tpl(W, Word, INTRIN)               \
    112 R123_STATIC_INLINE Word mulhilo##W(Word a, Word b, Word* hip){       \
    113     return INTRIN(a, b, hip);                                   \
    114 }
    115 
    116 /* N.B.  This really should be called _mulhilo_mulhi_intrin.  It just
    117    happens that CUDA was the first time we used the idiom. */
    118 #define _mulhilo_cuda_intrin_tpl(W, Word, INTRIN)                       \
    119 R123_CUDA_DEVICE R123_STATIC_INLINE Word mulhilo##W(Word a, Word b, R123_METAL_THREAD_ADDRESS_SPACE Word* hip){ \
    120     *hip = INTRIN(a, b);                                                \
    121     return a*b;                                                         \
    122 }
    123 
    124 /*
    125 // A template for mulhilo using only word-size operations and
    126 // C99 operators (no adc, no mulhi).  It
    127 // requires four multiplies and a dozen or so shifts, adds
    128 // and tests.  It's *SLOW*.  It can be used to
    129 // implement philoxNx32 on platforms that completely lack
    130 // 64-bit types, e.g., Metal.  
    131 // On 32-bit platforms, it could be used to
    132 // implement philoxNx64, but on such platforms both the philoxNx32
    133 // and the threefryNx64 cbrngs are going to have much better
    134 // performance.  It is enabled below by R123_USE_MULHILO64_C99,
    135 // but that is currently (Feb 2019) only set by 
    136 // features/metalfeatures.h headers.  It can, of course, be
    137 // set with a compile-time -D option.
    138 */
    139 #define _mulhilo_c99_tpl(W, Word) \
    140 R123_STATIC_INLINE Word mulhilo##W(Word a, Word b, R123_METAL_THREAD_ADDRESS_SPACE Word *hip){ \
    141     const unsigned WHALF = W/2;                                    \
    142     const Word LOMASK = ((((Word)1)<<WHALF)-1);                    \
    143     Word lo = a*b;               /* full low multiply */           \
    144     Word ahi = a>>WHALF;                                           \
    145     Word alo = a& LOMASK;                                          \
    146     Word bhi = b>>WHALF;                                           \
    147     Word blo = b& LOMASK;                                          \
    148                                                                    \
    149     Word ahbl = ahi*blo;                                           \
    150     Word albh = alo*bhi;                                           \
    151                                                                    \
    152     Word ahbl_albh = ((ahbl&LOMASK) + (albh&LOMASK));                   \
    153     Word hi = ahi*bhi + (ahbl>>WHALF) +  (albh>>WHALF);                 \
    154     hi += ahbl_albh >> WHALF; /* carry from the sum of lo(ahbl) + lo(albh) ) */ \
    155     /* carry from the sum with alo*blo */                               \
    156     hi += ((lo >> WHALF) < (ahbl_albh&LOMASK));                         \
    157     *hip = hi;                                                          \
    158     return lo;                                                          \
    159 }
    160 
    161 /*
    162 // A template for mulhilo on a platform that can't do it
    163 // We could put a C version here, but is it better to run *VERY*
    164 // slowly or to just stop and force the user to find another CBRNG?
    165 */
    166 #define _mulhilo_fail_tpl(W, Word)                                      \
    167 R123_STATIC_INLINE Word mulhilo##W(Word a, Word b, Word *hip){               \
    168     R123_STATIC_ASSERT(0, "mulhilo" #W " is not implemented on this machine\n"); \
    169 }
    170 
    171 /*
    172 // N.B.  There's an MSVC intrinsic called _emul,
    173 // which *might* compile into better code than
    174 // _mulhilo_dword_tpl 
    175 */
    176 #if R123_USE_MULHILO32_ASM
    177 #ifdef __powerpc__
    178 _mulhilo_asm_tpl(32, uint32_t, "mulhwu")
    179 #else
    180 _mulhilo_asm_tpl(32, uint32_t, "mull")
    181 #endif /* __powerpc__ */
    182 #else
    183 #if R123_USE_64BIT
    184 _mulhilo_dword_tpl(32, uint32_t, uint64_t)
    185 #elif R123_USE_MULHILO32_MULHI_INTRIN
    186 _mulhilo_cuda_intrin_tpl(32, uint32_t, R123_MULHILO32_MULHI_INTRIN)
    187 #else
    188 _mulhilo_c99_tpl(32, uint32_t)
    189 #endif
    190 #endif
    191 
    192 #if R123_USE_PHILOX_64BIT
    193 #if R123_USE_MULHILO64_ASM
    194 #ifdef __powerpc64__
    195 _mulhilo_asm_tpl(64, uint64_t, "mulhdu")
    196 #else
    197 _mulhilo_asm_tpl(64, uint64_t, "mulq")
    198 #endif /* __powerpc64__ */
    199 #elif R123_USE_MULHILO64_MSVC_INTRIN
    200 _mulhilo_msvc_intrin_tpl(64, uint64_t, _umul128)
    201 #elif R123_USE_MULHILO64_CUDA_INTRIN
    202 _mulhilo_cuda_intrin_tpl(64, uint64_t, __umul64hi)
    203 #elif R123_USE_MULHILO64_OPENCL_INTRIN
    204 _mulhilo_cuda_intrin_tpl(64, uint64_t, mul_hi)
    205 #elif R123_USE_MULHILO64_MULHI_INTRIN
    206 _mulhilo_cuda_intrin_tpl(64, uint64_t, R123_MULHILO64_MULHI_INTRIN)
    207 #elif R123_USE_GNU_UINT128
    208 _mulhilo_dword_tpl(64, uint64_t, __uint128_t)
    209 #elif R123_USE_MULHILO64_C99
    210 _mulhilo_c99_tpl(64, uint64_t)
    211 #else
    212 _mulhilo_fail_tpl(64, uint64_t)
    213 #endif
    214 #endif
    215 
    216 /*
    217 // The multipliers and Weyl constants are "hard coded".
    218 // To change them, you can #define them with different
    219 // values before #include-ing this file. 
    220 // This isn't terribly elegant, but it works for C as
    221 // well as C++.  A nice C++-only solution would be to
    222 // use template parameters in the style of <random>
    223 */
    224 #ifndef PHILOX_M2x64_0
    225 #define PHILOX_M2x64_0 R123_64BIT(0xD2B74407B1CE6E93)
    226 #endif
    227 
    228 #ifndef PHILOX_M4x64_0
    229 #define PHILOX_M4x64_0 R123_64BIT(0xD2E7470EE14C6C93)
    230 #endif
    231 
    232 #ifndef PHILOX_M4x64_1
    233 #define PHILOX_M4x64_1 R123_64BIT(0xCA5A826395121157)
    234 #endif
    235 
    236 #ifndef PHILOX_M2x32_0
    237 #define PHILOX_M2x32_0 ((uint32_t)0xd256d193)
    238 #endif
    239 
    240 #ifndef PHILOX_M4x32_0
    241 #define PHILOX_M4x32_0 ((uint32_t)0xD2511F53)
    242 #endif
    243 #ifndef PHILOX_M4x32_1
    244 #define PHILOX_M4x32_1 ((uint32_t)0xCD9E8D57)
    245 #endif
    246 
    247 #ifndef PHILOX_W64_0
    248 #define PHILOX_W64_0 R123_64BIT(0x9E3779B97F4A7C15)  /* golden ratio */
    249 #endif
    250 #ifndef PHILOX_W64_1
    251 #define PHILOX_W64_1 R123_64BIT(0xBB67AE8584CAA73B)  /* sqrt(3)-1 */
    252 #endif
    253 
    254 #ifndef PHILOX_W32_0
    255 #define PHILOX_W32_0 ((uint32_t)0x9E3779B9)
    256 #endif
    257 #ifndef PHILOX_W32_1
    258 #define PHILOX_W32_1 ((uint32_t)0xBB67AE85)
    259 #endif
    260 
    261 /** \endcond */
    262 #ifndef PHILOX2x32_DEFAULT_ROUNDS
    263 #define PHILOX2x32_DEFAULT_ROUNDS 10
    264 #endif
    265 
    266 #ifndef PHILOX2x64_DEFAULT_ROUNDS
    267 #define PHILOX2x64_DEFAULT_ROUNDS 10
    268 #endif
    269 
    270 #ifndef PHILOX4x32_DEFAULT_ROUNDS
    271 #define PHILOX4x32_DEFAULT_ROUNDS 10
    272 #endif
    273 
    274 #ifndef PHILOX4x64_DEFAULT_ROUNDS
    275 #define PHILOX4x64_DEFAULT_ROUNDS 10
    276 #endif
    277 /** \cond HIDDEN_FROM_DOXYGEN */
    278 
    279 /* The ignored fourth argument allows us to instantiate the
    280    same macro regardless of N. */
    281 #define _philox2xWround_tpl(W, T)                                       \
    282 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(struct r123array2x##W _philox2x##W##round(struct r123array2x##W ctr, struct r123array1x##W key)); \
    283 R123_CUDA_DEVICE R123_STATIC_INLINE struct r123array2x##W _philox2x##W##round(struct r123array2x##W ctr, struct r123array1x##W key){ \
    284     T hi;                                                               \
    285     T lo = mulhilo##W(PHILOX_M2x##W##_0, ctr.v[0], &hi);                \
    286     struct r123array2x##W out = {{hi^key.v[0]^ctr.v[1], lo}};               \
    287     return out;                                                         \
    288 }
    289 #define _philox2xWbumpkey_tpl(W)                                        \
    290 R123_CUDA_DEVICE R123_STATIC_INLINE struct r123array1x##W _philox2x##W##bumpkey( struct r123array1x##W key) { \
    291     key.v[0] += PHILOX_W##W##_0;                                        \
    292     return key;                                                         \
    293 }
    294 
    295 #define _philox4xWround_tpl(W, T)                                       \
    296 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(struct r123array4x##W _philox4x##W##round(struct r123array4x##W ctr, struct r123array2x##W key)); \
    297 R123_CUDA_DEVICE R123_STATIC_INLINE struct r123array4x##W _philox4x##W##round(struct r123array4x##W ctr, struct r123array2x##W key){ \
    298     T hi0;                                                              \
    299     T hi1;                                                              \
    300     T lo0 = mulhilo##W(PHILOX_M4x##W##_0, ctr.v[0], &hi0);              \
    301     T lo1 = mulhilo##W(PHILOX_M4x##W##_1, ctr.v[2], &hi1);              \
    302     struct r123array4x##W out = {{hi1^ctr.v[1]^key.v[0], lo1,               \
    303                               hi0^ctr.v[3]^key.v[1], lo0}};             \
    304     return out;                                                         \
    305 }
    306 
    307 #define _philox4xWbumpkey_tpl(W)                                        \
    308 R123_CUDA_DEVICE R123_STATIC_INLINE struct r123array2x##W _philox4x##W##bumpkey( struct r123array2x##W key) { \
    309     key.v[0] += PHILOX_W##W##_0;                                        \
    310     key.v[1] += PHILOX_W##W##_1;                                        \
    311     return key;                                                         \
    312 }
    313 
    314 /** \endcond */
    315 #define _philoxNxW_tpl(N, Nhalf, W, T)                         \
    316 /** @ingroup PhiloxNxW */                                       \
    317 enum r123_enum_philox##N##x##W { philox##N##x##W##_rounds = PHILOX##N##x##W##_DEFAULT_ROUNDS }; \
    318 typedef struct r123array##N##x##W philox##N##x##W##_ctr_t;                  \
    319 typedef struct r123array##Nhalf##x##W philox##N##x##W##_key_t;              \
    320 typedef struct r123array##Nhalf##x##W philox##N##x##W##_ukey_t;              \
    321 R123_CUDA_DEVICE R123_STATIC_INLINE philox##N##x##W##_key_t philox##N##x##W##keyinit(philox##N##x##W##_ukey_t uk) { return uk; } \
    322 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(philox##N##x##W##_ctr_t philox##N##x##W##_R(unsigned int R, philox##N##x##W##_ctr_t ctr, philox##N##x##W##_key_t key)); \
    323 R123_CUDA_DEVICE R123_STATIC_INLINE philox##N##x##W##_ctr_t philox##N##x##W##_R(unsigned int R, philox##N##x##W##_ctr_t ctr, philox##N##x##W##_key_t key) { \
    324     R123_ASSERT(R<=16);                                                 \
    325     if(R>0){                                       ctr = _philox##N##x##W##round(ctr, key); } \
    326     if(R>1){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    327     if(R>2){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    328     if(R>3){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    329     if(R>4){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    330     if(R>5){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    331     if(R>6){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    332     if(R>7){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    333     if(R>8){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    334     if(R>9){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    335     if(R>10){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    336     if(R>11){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    337     if(R>12){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    338     if(R>13){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    339     if(R>14){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    340     if(R>15){ key = _philox##N##x##W##bumpkey(key); ctr = _philox##N##x##W##round(ctr, key); } \
    341     return ctr;                                                         \
    342 }
    343          
    344 _philox2xWbumpkey_tpl(32)
    345 _philox4xWbumpkey_tpl(32)
    346 _philox2xWround_tpl(32, uint32_t) /* philox2x32round */
    347 _philox4xWround_tpl(32, uint32_t)            /* philo4x32round */
    348 
    349 _philoxNxW_tpl(2, 1, 32, uint32_t)    /* philox2x32bijection */
    350 _philoxNxW_tpl(4, 2, 32, uint32_t)    /* philox4x32bijection */
    351 #if R123_USE_PHILOX_64BIT
    352 /** \cond HIDDEN_FROM_DOXYGEN */
    353 _philox2xWbumpkey_tpl(64)
    354 _philox4xWbumpkey_tpl(64)
    355 _philox2xWround_tpl(64, uint64_t) /* philo2x64round */
    356 _philox4xWround_tpl(64, uint64_t) /* philo4x64round */
    357 /** \endcond */
    358 _philoxNxW_tpl(2, 1, 64, uint64_t)    /* philox2x64bijection */
    359 _philoxNxW_tpl(4, 2, 64, uint64_t)    /* philox4x64bijection */
    360 #endif /* R123_USE_PHILOX_64BIT */
    361 
    362 #define philox2x32(c,k) philox2x32_R(philox2x32_rounds, c, k)
    363 #define philox4x32(c,k) philox4x32_R(philox4x32_rounds, c, k)
    364 #if R123_USE_PHILOX_64BIT
    365 #define philox2x64(c,k) philox2x64_R(philox2x64_rounds, c, k)
    366 #define philox4x64(c,k) philox4x64_R(philox4x64_rounds, c, k)
    367 #endif /* R123_USE_PHILOX_64BIT */
    368 
    369 #if defined(__cplusplus) 
    370 
    371 #define _PhiloxNxW_base_tpl(CType, KType, N, W)                         \
    372 namespace r123{                                                          \
    373 template<unsigned int ROUNDS>                                             \
    374 struct Philox##N##x##W##_R{                                             \
    375     typedef CType ctr_type;                                         \
    376     typedef KType key_type;                                             \
    377     typedef KType ukey_type;                                         \
    378     static const R123_METAL_CONSTANT_ADDRESS_SPACE unsigned int rounds=ROUNDS;				\
    379     inline R123_CUDA_DEVICE R123_FORCE_INLINE(ctr_type operator()(ctr_type ctr, key_type key) const){ \
    380         R123_STATIC_ASSERT(ROUNDS<=16, "philox is only unrolled up to 16 rounds\n"); \
    381         return philox##N##x##W##_R(ROUNDS, ctr, key);                       \
    382     }                                                                   \
    383 };                                                                      \
    384 typedef Philox##N##x##W##_R<philox##N##x##W##_rounds> Philox##N##x##W; \
    385  } // namespace r123
    386 
    387 _PhiloxNxW_base_tpl(r123array2x32, r123array1x32, 2, 32) // Philox2x32_R<R>
    388 _PhiloxNxW_base_tpl(r123array4x32, r123array2x32, 4, 32) // Philox4x32_R<R>
    389 #if R123_USE_PHILOX_64BIT
    390 _PhiloxNxW_base_tpl(r123array2x64, r123array1x64, 2, 64) // Philox2x64_R<R>
    391 _PhiloxNxW_base_tpl(r123array4x64, r123array2x64, 4, 64) // Philox4x64_R<R>
    392 #endif
    393 
    394 /* The _tpl macros don't quite work to do string-pasting inside comments.
    395    so we just write out the boilerplate documentation four times... */
    396 
    397 /** 
    398 @defgroup PhiloxNxW Philox Classes and Typedefs
    399 
    400 The PhiloxNxW classes export the member functions, typedefs and
    401 operator overloads required by a @ref CBRNG "CBRNG" class.
    402 
    403 As described in  
    404 <a href="http://dl.acm.org/citation.cfm?doid=2063405"><i>Parallel Random Numbers:  As Easy as 1, 2, 3</i> </a>.
    405 The Philox family of counter-based RNGs use integer multiplication, xor and permutation of W-bit words
    406 to scramble its N-word input key.  Philox is a mnemonic for Product HI LO Xor).
    407 
    408 
    409 @class r123::Philox2x32_R 
    410 @ingroup PhiloxNxW
    411 
    412 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    413 
    414 The template argument, ROUNDS, is the number of times the Philox round
    415 function will be applied.
    416 
    417 As of November 2011, the authors know of no statistical flaws with
    418 ROUNDS=6 or more for Philox2x32.
    419 
    420 @typedef r123::Philox2x32
    421 @ingroup PhiloxNxW
    422   Philox2x32 is equivalent to Philox2x32_R<10>.    With 10 rounds,
    423   Philox2x32 has a considerable safety margin over the minimum number
    424   of rounds with no known statistical flaws, but still has excellent
    425    performance. 
    426 
    427 
    428 
    429 @class r123::Philox2x64_R 
    430 @ingroup PhiloxNxW
    431 
    432 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    433 
    434 The template argument, ROUNDS, is the number of times the Philox round
    435 function will be applied.
    436 
    437 As of September 2011, the authors know of no statistical flaws with
    438 ROUNDS=6 or more for Philox2x64.
    439 
    440 @typedef r123::Philox2x64
    441 @ingroup PhiloxNxW
    442   Philox2x64 is equivalent to Philox2x64_R<10>.    With 10 rounds,
    443   Philox2x64 has a considerable safety margin over the minimum number
    444   of rounds with no known statistical flaws, but still has excellent
    445    performance. 
    446 
    447 
    448 
    449 @class r123::Philox4x32_R 
    450 @ingroup PhiloxNxW
    451 
    452 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    453 
    454 The template argument, ROUNDS, is the number of times the Philox round
    455 function will be applied.
    456 
    457 In November 2011, the authors recorded some suspicious p-values (approximately 1.e-7) from
    458 some very long (longer than the default BigCrush length) SimpPoker tests.  Despite
    459 the fact that even longer tests reverted to "passing" p-values, a cloud remains over
    460 Philox4x32 with 7 rounds.  The authors know of no statistical flaws with
    461 ROUNDS=8 or more for Philox4x32.
    462 
    463 @typedef r123::Philox4x32
    464 @ingroup PhiloxNxW
    465   Philox4x32 is equivalent to Philox4x32_R<10>.    With 10 rounds,
    466   Philox4x32 has a considerable safety margin over the minimum number
    467   of rounds with no known statistical flaws, but still has excellent
    468    performance. 
    469 
    470 
    471 
    472 @class r123::Philox4x64_R 
    473 @ingroup PhiloxNxW
    474 
    475 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    476 
    477 The template argument, ROUNDS, is the number of times the Philox round
    478 function will be applied.
    479 
    480 As of September 2011, the authors know of no statistical flaws with
    481 ROUNDS=7 or more for Philox4x64.
    482 
    483 @typedef r123::Philox4x64
    484 @ingroup PhiloxNxW
    485   Philox4x64 is equivalent to Philox4x64_R<10>.    With 10 rounds,
    486   Philox4x64 has a considerable safety margin over the minimum number
    487   of rounds with no known statistical flaws, but still has excellent
    488    performance. 
    489 */
    490 
    491 #endif /* __cplusplus */
    492 
    493 #endif /* _philox_dot_h_ */