HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_XorShift.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_XorShift.h (UT Library, C++)
7  *
8  * COMMENTS: Implementation of an XorShift128+ pseudorandom number generator,
9  * faster and better quality than Mersenne Twister, but
10  * with a shorter period of only pow(2,128)-1, or over 10 trillion
11  * years at 1 billion numbers per nanosecond. Alternatively,
12  * with 10 billion differently-seeded generators each generating 1
13  * trillion numbers, there is a 0.00003% chance of having two of
14  * the 10 billion sequences overlap somewhere.
15  */
16 
17 #ifndef __UT_XorShift__
18 #define __UT_XorShift__
19 
20 #include <SYS/SYS_BitUtil.h>
21 #include <SYS/SYS_Inline.h>
22 #include <SYS/SYS_Math.h>
23 #include <SYS/SYS_Types.h>
24 
26 {
27 public:
28  // NOTE: Default constructor leaves state uninitialized, to avoid cost
29  // of extra reseed if it will just be reseeded before its first use
30  // anyway.
33  {
34  reseed(seed0, seed1);
35  }
36  SYS_FORCE_INLINE UT_XorShift(uint32 seed0, uint32 seed1 = 0, uint32 seed2 = 0, uint32 seed3 = 0)
37  {
38  reseed(seed0, seed1, seed2, seed3);
39  }
40 
41  /// This is useful for after copy constructing from another UT_XorShift.
42  /// It will give a new random number sequence, consistently dependent
43  /// on (though uncorrelated with) the original, without affecting the
44  /// original.
46  {
47  reseed(state[0], state[1]);
48  }
49  void reseed(uint64 seed0, uint64 seed1 = 0)
50  {
51  // NOTE: Yes, the seeds must be mangled here, else there's a very
52  // long burn-in period as the dependence on each bit cycles
53  // around. It is critical that either state[0] or state[3]
54  // depends on all seeds. It does *not* suffice to just
55  // individually mangle the seeds and do a few get() calls.
56  uint64 seed01 = SYSwang_inthash64(seed0);
57  state[0] = seed01;
58  seed01 ^= seed1;
59  seed01 = SYSwang_inthash64(seed01);
60  state[1] = seed01;
61  // NOTE: The state must be seeded so that it is not everywhere zero.
62  if (seed01 == 0 && state[0] == 0)
63  {
64  // Arbitrary random bits
65  state[0] = 0xdd8d9063f8c6a49aULL;
66  state[1] = 0x5b3f183183528aaaULL;
67  }
68  }
69  SYS_FORCE_INLINE void reseed(uint32 seed0, uint32 seed1 = 0, uint32 seed2 = 0, uint32 seed3 = 0)
70  {
71  reseed(uint64(seed0) | (uint64(seed1)<<32), uint64(seed2) | (uint64(seed3)<<32));
72  }
74  {
75  // xorshift128+ algorithm:
76  // fastest generator passing BigCrush without systematic errors
77  uint64 s1 = state[0];
78  const uint64 s0 = state[1];
79  state[0] = s0;
80  s1 ^= (s1 << 23);
81  s1 = (s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26));
82  state[1] = s1;
83  return s1 + s0;
84  }
86  {
87  return uint32(get64());
88 #if 0
89  // xorshift128
90  uint32 temp = state[0] ^ (state[0] << 11);
91  state[0] = state[1];
92  state[1] = state[2];
93  state[2] = state[3];
94  state[3] = state[3] ^ (state[3] >> 19) ^ temp ^ (temp >> 8);
95  return state[3];
96 #endif
97  }
99  {
100  return intToFloat01(get());
101  }
103  {
104  return int64ToDouble01(get64());
105  }
106 
108  {
109  if (i == 0)
110  return 0.0f;
111  int e = SYSlastBitSet(i);
112  i <<= (31-e);
114  return *(fpreal32*)&i;
115  }
117  {
118  if (i == 0)
119  return 0.0;
120  int e = SYSlastBitSet(i);
121  i <<= (63-e);
123  return *(fpreal64*)&i;
124  }
125 #if 0
126  // Interface for compatibility with UT_MersenneTwister
127 
128  uint32 urandom() { return get(); }
129  float frandom() { return getFloat(); }
130  void setSeed(const uint32 *seeds, exint nseeds)
131  {
132  uint32 combinedseeds[4] = {0, 0, 0, 0};
133  exint m = SYSmin(nseeds, 4);
134  for (exint i = 0; i < m; ++i)
135  combinedseeds[i] = seeds[i];
136  for (exint i = 4; i < nseeds; ++i)
137  combinedseeds[i & 0x3] = uint32(SYSwang_inthash64((uint64(seeds[i])<<32) | uint64(combinedseeds[i & 0x3])));
138  reseed(combinedseeds[0], combinedseeds[1], combinedseeds[2], combinedseeds[3]);
139  }
140 #endif
141 
142 private:
143  uint64 state[2];
144 };
145 
147 {
148 public:
149  // NOTE: Default constructor leaves state uninitialized, to avoid cost
150  // of extra reseed if it will just be reseeded before its first use
151  // anyway.
154  {
155  reseed(seed0, seed1);
156  }
157  SYS_FORCE_INLINE UT_XorShiftCached(uint32 seed0, uint32 seed1 = 0, uint32 seed2 = 0, uint32 seed3 = 0)
158  {
159  reseed(seed0, seed1, seed2, seed3);
160  }
161  SYS_FORCE_INLINE void reseed(uint32 seed0, uint32 seed1 = 0, uint32 seed2 = 0, uint32 seed3 = 0)
162  {
163  reseed(uint64(seed0) | (uint64(seed1)<<32), uint64(seed2) | (uint64(seed3)<<32));
164  }
165  void reseed(uint64 seed0, uint64 seed1 = 0)
166  {
167  UT_XorShift::reseed(seed0, seed1);
168  myHasCached = false;
169  }
171  {
172  if (myHasCached)
173  {
174  myHasCached = false;
175  return myCached;
176  }
177  uint64 result = get64();
178  myCached = uint32(result >> 32);
179  myHasCached = true;
180  return uint32(result);
181  }
183  {
184  return intToFloat01(get());
185  }
186 private:
187  uint32 myCached;
188  bool myHasCached;
189 };
190 
191 #endif
SYS_FORCE_INLINE float getFloat()
Definition: UT_XorShift.h:98
void reseed(uint64 seed0, uint64 seed1=0)
Definition: UT_XorShift.h:165
void reseed(uint64 seed0, uint64 seed1=0)
Definition: UT_XorShift.h:49
SYS_FORCE_INLINE void reseedSelf()
Definition: UT_XorShift.h:45
SYS_FORCE_INLINE UT_XorShiftCached()
Definition: UT_XorShift.h:152
int64 exint
Definition: SYS_Types.h:125
**But if you need a result
Definition: thread.h:613
unsigned long long uint64
Definition: SYS_Types.h:117
float fpreal32
Definition: SYS_Types.h:200
double fpreal64
Definition: SYS_Types.h:201
SYS_FORCE_INLINE UT_XorShift(uint32 seed0, uint32 seed1=0, uint32 seed2=0, uint32 seed3=0)
Definition: UT_XorShift.h:36
SYS_FORCE_INLINE UT_XorShiftCached(uint64 seed0, uint64 seed1=0)
Definition: UT_XorShift.h:153
SYS_FORCE_INLINE UT_XorShiftCached(uint32 seed0, uint32 seed1=0, uint32 seed2=0, uint32 seed3=0)
Definition: UT_XorShift.h:157
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
SYS_FORCE_INLINE void reseed(uint32 seed0, uint32 seed1=0, uint32 seed2=0, uint32 seed3=0)
Definition: UT_XorShift.h:69
static SYS_FORCE_INLINE fpreal64 int64ToDouble01(uint64 i)
Definition: UT_XorShift.h:116
SYS_FORCE_INLINE void reseed(uint32 seed0, uint32 seed1=0, uint32 seed2=0, uint32 seed3=0)
Definition: UT_XorShift.h:161
SYS_FORCE_INLINE float getFloat()
Definition: UT_XorShift.h:182
static SYS_FORCE_INLINE fpreal32 intToFloat01(uint32 i)
Definition: UT_XorShift.h:107
unsigned int uint32
Definition: SYS_Types.h:40
SYS_FORCE_INLINE UT_XorShift(uint64 seed0, uint64 seed1=0)
Definition: UT_XorShift.h:32
SYS_FORCE_INLINE uint64 get64()
Definition: UT_XorShift.h:73
#define SYSmin(a, b)
Definition: SYS_Math.h:1571
SYS_FORCE_INLINE UT_XorShift()
Definition: UT_XorShift.h:31
SYS_FORCE_INLINE double getDouble()
Definition: UT_XorShift.h:102