mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-06 00:55:37 +00:00
e1252e4e42
--HG-- extra : rebase_source : 3eb009156765b341e6a2dcee9f0287ce198c439f
98 lines
3.2 KiB
C++
98 lines
3.2 KiB
C++
/* -*- 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 <math.h>
|
|
#include <memory.h>
|
|
#include <stdint.h>
|
|
|
|
namespace mozilla {
|
|
namespace non_crypto {
|
|
|
|
/*
|
|
* 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<double>::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<double>::kExponentShift + 1;
|
|
uint64_t mantissa = next() & ((1ULL << kMantissaBits) - 1);
|
|
return ldexp(static_cast<double>(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 non_crypto
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_XorShift128Plus_h
|