/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* The xorshift128+ pseudo-random number generator. */ #ifndef mozilla_XorShift128Plus_h #define mozilla_XorShift128Plus_h #include "mozilla/Assertions.h" #include "mozilla/FloatingPoint.h" #include #include #include namespace mozilla { /* * A stream of pseudo-random numbers generated using the xorshift+ technique * described here: * * Vigna, Sebastiano (2014). "Further scramblings of Marsaglia's xorshift * generators". arXiv:1404.0390 (http://arxiv.org/abs/1404.0390) * * That paper says: * * In particular, we propose a tightly coded xorshift128+ generator that * does not fail systematically any test from the BigCrush suite of TestU01 * (even reversed) and generates 64 pseudorandom bits in 1.10 ns on an * Intel(R) Core(TM) i7-4770 CPU @3.40GHz (Haswell). It is the fastest * generator we are aware of with such empirical statistical properties. * * This generator is not suitable as a cryptographically secure random number * generator. */ class XorShift128PlusRNG { uint64_t mState[2]; public: /* * Construct a xorshift128+ pseudo-random number stream using |aInitial0| and * |aInitial1| as the initial state. These may not both be zero; ideally, they * should have an almost even mix of zero and one bits. */ XorShift128PlusRNG(uint64_t aInitial0, uint64_t aInitial1) { setState(aInitial0, aInitial1); } /* Return a pseudo-random 64-bit number. */ uint64_t next() { uint64_t s1 = mState[0]; const uint64_t s0 = mState[1]; mState[0] = s0; s1 ^= s1 << 23; mState[1] = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26); return mState[1] + s0; } /* * Return a pseudo-random floating-point value in the range [0, 1). * More precisely, choose an integer in the range [0, 2**53) and * divide it by 2**53. */ double nextDouble() { /* * Because the IEEE 64-bit floating point format stores the leading '1' bit * of the mantissa implicitly, it effectively represents a mantissa in the * range [0, 2**53) in only 52 bits. FloatingPoint::kExponentShift * is the width of the bitfield in the in-memory format, so we must add one * to get the mantissa's range. */ static const int kMantissaBits = mozilla::FloatingPoint::kExponentShift + 1; uint64_t mantissa = next() & ((1ULL << kMantissaBits) - 1); return ldexp(mantissa, -kMantissaBits); } /* * Set the stream's current state to |aState0| and |aState1|. These must not * both be zero; ideally, they should have an almost even mix of zero and one * bits. */ void setState(uint64_t aState0, uint64_t aState1) { MOZ_ASSERT(aState0 || aState1); mState[0] = aState0; mState[1] = aState1; } }; } // namespace mozilla #endif // mozilla_XorShift128Plus_h