XorShift128PlusRNG.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* The xorshift128+ pseudo-random number generator. */
  6. #ifndef mozilla_XorShift128Plus_h
  7. #define mozilla_XorShift128Plus_h
  8. #include "mozilla/Assertions.h"
  9. #include "mozilla/Attributes.h"
  10. #include "mozilla/FloatingPoint.h"
  11. #include <inttypes.h>
  12. namespace mozilla {
  13. namespace non_crypto {
  14. /*
  15. * A stream of pseudo-random numbers generated using the xorshift+ technique
  16. * described here:
  17. *
  18. * Vigna, Sebastiano (2014). "Further scramblings of Marsaglia's xorshift
  19. * generators". arXiv:1404.0390 (http://arxiv.org/abs/1404.0390)
  20. *
  21. * That paper says:
  22. *
  23. * In particular, we propose a tightly coded xorshift128+ generator that
  24. * does not fail systematically any test from the BigCrush suite of TestU01
  25. * (even reversed) and generates 64 pseudorandom bits in 1.10 ns on an
  26. * Intel(R) Core(TM) i7-4770 CPU @3.40GHz (Haswell). It is the fastest
  27. * generator we are aware of with such empirical statistical properties.
  28. *
  29. * The stream of numbers produced by this method repeats every 2**128 - 1 calls
  30. * (i.e. never, for all practical purposes). Zero appears 2**64 - 1 times in
  31. * this period; all other numbers appear 2**64 times. Additionally, each *bit*
  32. * in the produced numbers repeats every 2**128 - 1 calls.
  33. *
  34. * This generator is not suitable as a cryptographically secure random number
  35. * generator.
  36. */
  37. class XorShift128PlusRNG {
  38. uint64_t mState[2];
  39. public:
  40. /*
  41. * Construct a xorshift128+ pseudo-random number stream using |aInitial0| and
  42. * |aInitial1| as the initial state. These MUST NOT both be zero.
  43. *
  44. * If the initial states contain many zeros, for a few iterations you'll see
  45. * many zeroes in the generated numbers. It's suggested to seed a SplitMix64
  46. * generator <http://xorshift.di.unimi.it/splitmix64.c> and use its first two
  47. * outputs to seed xorshift128+.
  48. */
  49. XorShift128PlusRNG(uint64_t aInitial0, uint64_t aInitial1) {
  50. setState(aInitial0, aInitial1);
  51. }
  52. /**
  53. * Return a pseudo-random 64-bit number.
  54. */
  55. uint64_t next() {
  56. /*
  57. * The offsetOfState*() methods below are provided so that exceedingly-rare
  58. * callers that want to observe or poke at RNG state in C++ type-system-
  59. * ignoring means can do so. Don't change the next() or nextDouble()
  60. * algorithms without altering code that uses offsetOfState*()!
  61. */
  62. uint64_t s1 = mState[0];
  63. const uint64_t s0 = mState[1];
  64. mState[0] = s0;
  65. s1 ^= s1 << 23;
  66. mState[1] = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26);
  67. return mState[1] + s0;
  68. }
  69. /*
  70. * Return a pseudo-random floating-point value in the range [0, 1). More
  71. * precisely, choose an integer in the range [0, 2**53) and divide it by
  72. * 2**53. Given the 2**128 - 1 period noted above, the produced doubles are
  73. * all but uniformly distributed in this range.
  74. */
  75. double nextDouble() {
  76. /*
  77. * Because the IEEE 64-bit floating point format stores the leading '1' bit
  78. * of the mantissa implicitly, it effectively represents a mantissa in the
  79. * range [0, 2**53) in only 52 bits. FloatingPoint<double>::kExponentShift
  80. * is the width of the bitfield in the in-memory format, so we must add one
  81. * to get the mantissa's range.
  82. */
  83. static constexpr int kMantissaBits =
  84. mozilla::FloatingPoint<double>::kExponentShift + 1;
  85. uint64_t mantissa = next() & ((UINT64_C(1) << kMantissaBits) - 1);
  86. return double(mantissa) / (UINT64_C(1) << kMantissaBits);
  87. }
  88. /*
  89. * Set the stream's current state to |aState0| and |aState1|. These must not
  90. * both be zero; ideally, they should have an almost even mix of zero and one
  91. * bits.
  92. */
  93. void setState(uint64_t aState0, uint64_t aState1) {
  94. MOZ_ASSERT(aState0 || aState1);
  95. mState[0] = aState0;
  96. mState[1] = aState1;
  97. }
  98. static size_t offsetOfState0() {
  99. return offsetof(XorShift128PlusRNG, mState[0]);
  100. }
  101. static size_t offsetOfState1() {
  102. return offsetof(XorShift128PlusRNG, mState[1]);
  103. }
  104. };
  105. } // namespace non_crypto
  106. } // namespace mozilla
  107. #endif // mozilla_XorShift128Plus_h