1 /**************************************************************************\
3 * Middle Square Weyl Sequence Random Number Generator *
5 * msws() - returns a 32 bit unsigned int [0,0xffffffff] *
7 * The state vector consists of three 64 bit words: x, w, and s *
9 * x - random output [0,0xffffffff] *
10 * w - Weyl sequence (period 2^64) *
11 * s - an odd constant *
13 * The Weyl sequence is added to the square of x. The middle is extracted *
14 * by shifting right 32 bits: *
16 * x *= x; x += (w += s); return x = (x>>32) | (x<<32); *
18 * The constant s should be set to a random 64-bit pattern with the upper *
19 * 32 bits non-zero and the least significant bit set to 1. There are *
20 * on the order of 2^63 numbers of this type. Since the stream length *
21 * is 2^64, this provides about 2^127 random numbers in total. *
23 * Note: This version of the RNG includes an idea proposed by *
24 * Richard P. Brent (creator of the xorgens RNG). Brent suggested *
25 * adding the Weyl sequence after squaring instead of before squaring. *
26 * This provides a basis for uniformity in the output. *
28 * Copyright (c) 2014-2018 Bernard Widynski *
30 * This code can be used under the terms of the GNU General Public License *
31 * as published by the Free Software Foundation, either version 3 of the *
32 * License, or any later version. See the GPL license at URL *
33 * http://www.gnu.org/licenses *
35 \**************************************************************************/
37 /**************************************************************************\
39 * Modifications applied by LoRd_MuldeR <mulder2@gmx.de>: *
41 * 1. Added function to get random 32-Bit value with upper limit *
42 * 2. Added function to get random 64-Bit value *
43 * 3. Added function to get random byte-sequence of arbitrary length *
44 * 4. Improved initialization (seeding) function *
45 * 5. Made all functions thread-safe by avoiding the use of static vars *
46 * 6. Implemented C++ wrapper class, for convenience *
48 \**************************************************************************/
56 typedef uint64_t msws_t[3];
58 inline static uint32_t msws_uint32(msws_t ctx)
60 ctx[0] *= ctx[0]; ctx[0] += (ctx[1] += ctx[2]);
61 return (uint32_t)(ctx[0] = (ctx[0] >> 32) | (ctx[0] << 32));
64 static inline uint32_t msws_uint32_max(msws_t ctx, const uint32_t max)
66 static const uint32_t DIV[64] =
68 0xFFFFFFFF, 0xFFFFFFFF, 0x80000000, 0x55555556,
69 0x40000000, 0x33333334, 0x2AAAAAAB, 0x24924925,
70 0x20000000, 0x1C71C71D, 0x1999999A, 0x1745D175,
71 0x15555556, 0x13B13B14, 0x12492493, 0x11111112,
72 0x10000000, 0x0F0F0F10, 0x0E38E38F, 0x0D79435F,
73 0x0CCCCCCD, 0x0C30C30D, 0x0BA2E8BB, 0x0B21642D,
74 0x0AAAAAAB, 0x0A3D70A4, 0x09D89D8A, 0x097B425F,
75 0x0924924A, 0x08D3DCB1, 0x08888889, 0x08421085,
76 0x08000000, 0x07C1F07D, 0x07878788, 0x07507508,
77 0x071C71C8, 0x06EB3E46, 0x06BCA1B0, 0x06906907,
78 0x06666667, 0x063E7064, 0x06186187, 0x05F417D1,
79 0x05D1745E, 0x05B05B06, 0x0590B217, 0x0572620B,
80 0x05555556, 0x0539782A, 0x051EB852, 0x05050506,
81 0x04EC4EC5, 0x04D4873F, 0x04BDA130, 0x04A7904B,
82 0x04924925, 0x047DC120, 0x0469EE59, 0x0456C798,
83 0x04444445, 0x04325C54, 0x04210843, 0x04104105
86 ? (msws_uint32(ctx) / DIV[max])
87 : (msws_uint32(ctx) / (UINT32_MAX / max + 1U));
90 inline static uint64_t msws_uint64(msws_t ctx)
92 return (((uint64_t)msws_uint32(ctx)) << 32U) | msws_uint32(ctx);
95 inline static void msws_bytes(msws_t ctx, uint8_t *buffer, size_t len)
97 if (((len & 3U) == 0U) && ((((uintptr_t)buffer) & 3U) == 0U))
99 uint32_t *ptr = (uint32_t*)buffer;
100 for (len >>= 2U; len; --len)
102 *ptr++ = msws_uint32(ctx);
108 for(size_t sft = 0U; len; --len, sft = (sft + 1U) & 3U)
110 *buffer++ = (uint8_t)(sft ? (tmp >>= 8U) : (tmp = msws_uint32(ctx)));
115 inline static void msws_init(msws_t ctx, const uint32_t seed)
117 ctx[0] = UINT64_C(0); ctx[1] = UINT64_C(0);
118 ctx[2] = (((uint64_t)seed) << 1U) + 0xB5AD4ECEDA1CE2A9;
119 for (int i = 0; i < 13; ++i)
121 volatile uint32_t q = msws_uint32(ctx);