gradilac.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /**
  2. * gradilac.h version 4.3.7
  3. *
  4. * The inclusion file for the "Gradilac", a flexible templated C++ PRNG, based
  5. * on the PRVHASH core function. Standalone class, does not require PRVHASH
  6. * header files.
  7. *
  8. * Description is available at https://github.com/avaneev/prvhash
  9. *
  10. * License
  11. *
  12. * Copyright (c) 2022 Aleksey Vaneev
  13. *
  14. * Permission is hereby granted, free of charge, to any person obtaining a
  15. * copy of this software and associated documentation files (the "Software"),
  16. * to deal in the Software without restriction, including without limitation
  17. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  18. * and/or sell copies of the Software, and to permit persons to whom the
  19. * Software is furnished to do so, subject to the following conditions:
  20. *
  21. * The above copyright notice and this permission notice shall be included in
  22. * all copies or substantial portions of the Software.
  23. *
  24. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  27. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  29. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  30. * DEALINGS IN THE SOFTWARE.
  31. */
  32. #ifndef GRADILAC_INCLUDED
  33. #define GRADILAC_INCLUDED
  34. #include <stdint.h>
  35. #include <string.h>
  36. #include <math.h>
  37. /**
  38. * Templated PRVHASH core function. For more information, please refer to the
  39. * "prvhash_core64" function in the "prvhash_core.h" file.
  40. *
  41. * @param[in,out] Seed0 The current "Seed" value.
  42. * @param[in,out] lcg0 The current "lcg" value.
  43. * @param[in,out] Hash0 Current hashword in a hashword array.
  44. * @return Current random value.
  45. * @tparam stype State variable type, must be unsigned type, up to 64 bits.
  46. */
  47. template< typename stype >
  48. static inline stype prvhash_core( stype* const Seed0, stype* const lcg0,
  49. stype* const Hash0 )
  50. {
  51. const int sh = sizeof( stype ) * 4;
  52. stype Seed = *Seed0; stype lcg = *lcg0; stype Hash = *Hash0;
  53. Seed *= (stype) ( lcg * 2 + 1 );
  54. const stype rs = (stype) ( Seed >> sh | Seed << sh );
  55. Hash += (stype) ( rs + (stype) 0xAAAAAAAAAAAAAAAA );
  56. lcg += (stype) ( Seed + (stype) 0x5555555555555555 );
  57. Seed ^= Hash;
  58. const stype out = (stype) ( lcg ^ rs );
  59. *Seed0 = Seed; *lcg0 = lcg; *Hash0 = Hash;
  60. return( out );
  61. }
  62. /**
  63. * Generalized templated PRVHASH-based PRNG class.
  64. *
  65. * Objects of this class do not use memory allocations and can be placed on
  66. * stack (if "hcount" is not large).
  67. *
  68. * Note that random values returned by functions of this class return values
  69. * in the "exclusive" range only, [0; 1) or [0; N). Also note that precision
  70. * of floating-point random numbers depends on the "stype" in use.
  71. *
  72. * @tparam hcount The number of hashwords in array, must be >0. E.g. use 316
  73. * and 64-bit "stype" to match Mersenne Twister's PRNG period.
  74. * @tparam stype State variable type, must be unsigned integer type, up to 64
  75. * bits wide. Using "stype" smaller than 24 bits is not advised.
  76. * @tparam fuse PRVHASH fusing, must be > 0. Should be above 1 if PRNG output
  77. * may be used as entropy input (output feedback), usually in open systems.
  78. * @tparam cs Must be >= 0. If above 0, enable CSPRNG mode. "cs" defines the
  79. * number of additional PRNG rounds and XOR operations, 1 is usually enough.
  80. */
  81. template< size_t hcount = 1, typename stype = uint64_t, int fuse = 1,
  82. int cs = 0 >
  83. class Gradilac
  84. {
  85. public:
  86. /**
  87. * Constructor. Note that copy-constructor and copy operator remain
  88. * default as class has no complex structures.
  89. *
  90. * @param iseed Initial "small" seed, can be zero.
  91. */
  92. Gradilac( const stype iseed = 0 )
  93. {
  94. seed( iseed );
  95. }
  96. /**
  97. * Function initializes/reinitializes the PRNG. This is not the on-the-go
  98. * re-seeding. In CSPRNG mode, the "reseed" function should then be
  99. * called.
  100. *
  101. * @param iseed Initial "small" seed, can be zero.
  102. */
  103. void seed( const stype iseed = 0 )
  104. {
  105. memset( Seed, 0, fuse * sizeof( Seed[ 0 ]));
  106. memset( lcg, 0, fuse * sizeof( lcg[ 0 ]));
  107. memset( Hash, 0, hcount * sizeof( Hash[ 0 ]));
  108. Seed[ 0 ] = iseed;
  109. hpos = 0;
  110. BitPool = 0;
  111. BitsLeft = 0;
  112. // Initialization involving only the first hashword, other zero
  113. // hashwords will be initialized on the go: this approach was
  114. // well-tested, and PRNG does produce a valid random output while
  115. // initializing the hashwords.
  116. int j;
  117. for( j = 0; j < 5; j++ )
  118. {
  119. int i;
  120. for( i = 0; i < fuse; i++ )
  121. {
  122. prvhash_core( Seed + i, lcg + i, Hash + 0 );
  123. }
  124. }
  125. }
  126. /**
  127. * Function re-seeds PRNG on-the-go using a single entropy value. This
  128. * function is not advised for use in CSPRNG mode. This function can be
  129. * used to efficiently adjust initial seed after the default constructor
  130. * call (iseed=0).
  131. *
  132. * @param ent Entropy value (can be any value).
  133. */
  134. void reseed( const stype ent )
  135. {
  136. Seed[ 0 ] ^= ent;
  137. lcg[ 0 ] ^= ent;
  138. getRaw();
  139. if( fuse > 1 )
  140. {
  141. getRaw();
  142. }
  143. }
  144. /**
  145. * Function re-seeds PRNG, starting from the current state, and using the
  146. * specified data as entropy. This function should be used in CSPRNG mode.
  147. *
  148. * @param data Entropy data block, can be of any length and of any
  149. * statistical quality. Usually it is any sequence of physics-dependent
  150. * data from physical sources like timer, keyboard, mouse, network. Or
  151. * from system's CSPRNG.
  152. * @param dlen Data length, in bytes.
  153. * @param psize Packet size, in bytes, >= 1. Should not exceed the size of
  154. * "stype". The data will be divided into packets of this size per PRNG
  155. * advancement. This value affects initialization overhead. Value of 1 is
  156. * advised for sparsely-random data. High-quality entropy can use
  157. * sizeof( stype ).
  158. */
  159. void reseed( const void* const data, size_t dlen, const size_t psize = 1 )
  160. {
  161. const uint8_t* d = (const uint8_t*) data;
  162. while( dlen > 0 )
  163. {
  164. size_t l = ( psize > dlen ? dlen : psize );
  165. dlen -= l;
  166. stype p = 0; // Packet.
  167. while( l > 0 )
  168. {
  169. p <<= 8;
  170. p |= *d;
  171. d++;
  172. l--;
  173. }
  174. Seed[ 0 ] ^= p;
  175. lcg[ 0 ] ^= p;
  176. getRaw();
  177. }
  178. // Make hashword array pass to eliminate traces of input entropy.
  179. int i;
  180. for( i = 0; i < hcount + ( hcount > 1 ) + ( fuse > 1 ); i++ )
  181. {
  182. getRaw();
  183. }
  184. }
  185. /**
  186. * @return The next floating-point random number in [0; 1) range.
  187. */
  188. double get()
  189. {
  190. if( sizeof( stype ) * 8 > 53 )
  191. {
  192. return(( getRaw() >> ( sizeof( stype ) * 8 - 53 )) * 0x1p-53 );
  193. }
  194. else
  195. {
  196. return( getRaw() * im() );
  197. }
  198. }
  199. /**
  200. * @return The next floating-point random number in [0; N1) range.
  201. */
  202. double get( const double N1 )
  203. {
  204. if( sizeof( stype ) * 8 > 53 )
  205. {
  206. return(( getRaw() >> ( sizeof( stype ) * 8 - 53 )) *
  207. 0x1p-53 * N1 );
  208. }
  209. else
  210. {
  211. return( getRaw() * im() * N1 );
  212. }
  213. }
  214. /**
  215. * Operator "object as function", for easier integration, same as the
  216. * get() function.
  217. */
  218. double operator()()
  219. {
  220. return( get() );
  221. }
  222. /**
  223. * @return The next random integer number in the "raw", stype-value range.
  224. * This is the actual PRNG advancement function.
  225. */
  226. stype getRaw()
  227. {
  228. stype* h = Hash + hpos;
  229. if( ++hpos == hcount )
  230. {
  231. hpos = 0;
  232. }
  233. int i;
  234. for( i = 0; i < fuse - 1; i++ )
  235. {
  236. prvhash_core( Seed + i, lcg + i, h );
  237. }
  238. stype res = prvhash_core( Seed + i, lcg + i, h );
  239. int j;
  240. for( j = 0; j < cs; j++ )
  241. {
  242. h = Hash + hpos;
  243. if( ++hpos == hcount )
  244. {
  245. hpos = 0;
  246. }
  247. for( i = 0; i < fuse - 1; i++ )
  248. {
  249. prvhash_core( Seed + i, lcg + i, h );
  250. }
  251. res ^= prvhash_core( Seed + i, lcg + i, h );
  252. }
  253. return( res );
  254. }
  255. /**
  256. * @return The next random integer number in [0; N1) range (note the N's
  257. * exclusivity). N1 specifies positive number of discrete bins, and not
  258. * the extreme value.
  259. */
  260. int getInt( const int N1 )
  261. {
  262. return( (int) get( (double) N1 ));
  263. }
  264. /**
  265. * @return The next squared floating-point random number in [0; 1) range.
  266. * This is Beta distribution, with alpha=0.5, beta=1.
  267. */
  268. double getSqr()
  269. {
  270. const double v = get();
  271. return( v * v );
  272. }
  273. /**
  274. * @return TPDF random number in the range (-1; 1). Note that this
  275. * function uses an optimized variant, with 32-bit precision, when
  276. * stype=uint64_t.
  277. */
  278. double getTPDF()
  279. {
  280. if( sizeof( stype ) == 8 )
  281. {
  282. const stype rv = getRaw();
  283. return(( (int64_t) ( rv >> 32 ) - (int64_t) (uint32_t) rv ) *
  284. 0x1p-32 );
  285. }
  286. else
  287. if( sizeof( stype ) * 8 > 53 )
  288. {
  289. const double v1 = get();
  290. const double v2 = get();
  291. return( v1 - v2 );
  292. }
  293. else
  294. {
  295. const double v1 = (double) getRaw();
  296. const double v2 = (double) getRaw();
  297. return(( v1 - v2 ) * im() );
  298. }
  299. }
  300. /**
  301. * Function generates a Gaussian (normal)-distributed pseudo-random number
  302. * with mean=0 and std.dev=1.
  303. *
  304. * Algorithm is adopted from "Leva, J. L. 1992. "A Fast Normal Random
  305. * Number Generator", ACM Transactions on Mathematical Software, vol. 18,
  306. * no. 4, pp. 449-453".
  307. */
  308. double getNorm()
  309. {
  310. double q, u, v;
  311. do
  312. {
  313. u = get();
  314. v = get();
  315. if( u == 0.0 || v == 0.0 )
  316. {
  317. u = 1.0;
  318. v = 1.0;
  319. }
  320. v = 1.7156 * ( v - 0.5 );
  321. const double x = u - 0.449871;
  322. const double y = fabs( v ) + 0.386595;
  323. q = x * x + y * ( 0.19600 * y - 0.25472 * x );
  324. if( q < 0.27597 )
  325. {
  326. break;
  327. }
  328. } while( q > 0.27846 || v * v > -4.0 * log( u ) * u * u );
  329. return( v / u );
  330. }
  331. /**
  332. * Function generates a Gaussian (normal)-distributed pseudo-random number
  333. * with the specified mean and std.dev.
  334. */
  335. double getNorm( const double mean, const double stddev )
  336. {
  337. return( mean + stddev * getNorm() );
  338. }
  339. /**
  340. * @return The next random bit from the bit pool. Usually used for
  341. * efficient 50% probability evaluations.
  342. */
  343. int getBit()
  344. {
  345. if( BitsLeft == 0 )
  346. {
  347. BitPool = getRaw();
  348. const int b = (int) ( BitPool & 1 );
  349. BitsLeft = sizeof( stype ) * 8 - 1;
  350. BitPool >>= 1;
  351. return( b );
  352. }
  353. const int b = (int) ( BitPool & 1 );
  354. BitsLeft--;
  355. BitPool >>= 1;
  356. return( b );
  357. }
  358. /**
  359. * @return PRNG period's exponent (2^N) estimation.
  360. */
  361. static size_t getPeriodExp()
  362. {
  363. return(( fuse * 8 + fuse * 4 + hcount * 8 ) * sizeof( stype ) -
  364. hcount - cs );
  365. }
  366. protected:
  367. stype Seed[ fuse ]; ///< PRNG seeds (>1 - fused).
  368. stype lcg[ fuse ]; ///< PRNG lcg (>1 - fused).
  369. stype Hash[ hcount ]; ///< PRNG hash array.
  370. size_t hpos; ///< Hash array position (increments linearly, resets to 0).
  371. stype BitPool; ///< Bit pool, optional feature.
  372. int BitsLeft; ///< The number of bits left in the bit pool.
  373. /**
  374. * @return Inverse multiplier to scale stype's value range to [0; 1)
  375. * range.
  376. */
  377. static double im()
  378. {
  379. static const double v = 0.5 / ( 1ULL << ( sizeof( stype ) * 8 - 1 ));
  380. return( v );
  381. }
  382. };
  383. #endif // GRADILAC_INCLUDED