base: Use STL C++11 random number generation

This patch changes the random number generator from the in-house
Mersenne twister to an implementation relying entirely on C++11 STL.

The format for the checkpointing of the twister is simplified. As the
functionality was never used this should not matter. Note that this
patch does not actually make use of the checkpointing
functionality. As the random number generator is not thread safe, it
may be sensible to create one generator per thread, system, or even
object. Until this is decided the status quo is maintained in that no
generator state is part of the checkpoint.
This commit is contained in:
Andreas Hansson 2014-09-03 07:42:55 -04:00
parent 2698e73966
commit 83a46bfc09
4 changed files with 78 additions and 386 deletions

View file

@ -51,7 +51,6 @@ Source('misc.cc')
Source('output.cc')
Source('pollevent.cc')
Source('random.cc')
Source('random_mt.cc')
if env['TARGET_ISA'] != 'null':
Source('remote_gdb.cc')
Source('socket.cc')

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2014 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
@ -27,20 +39,18 @@
*
* Authors: Nathan Binkert
* Ali Saidi
* Andreas Hansson
*/
#include <limits>
#include "base/fenv.hh"
#include "base/intmath.hh"
#include <sstream>
#include "base/misc.hh"
#include "base/random.hh"
#include "sim/serialize.hh"
using namespace std;
Random::Random()
{
// default random seed taken from original source
// default random seed
init(5489);
}
@ -49,79 +59,41 @@ Random::Random(uint32_t s)
init(s);
}
Random::Random(uint32_t init_key[], int key_length)
{
init(init_key, key_length);
}
Random::~Random()
{
}
// To preserve the uniform random distribution between min and max,
// and allow all numbers to be represented, we generate a uniform
// random number to the nearest power of two greater than max. If
// this number doesn't fall between 0 and max, we try again. Anything
// else would skew the distribution.
uint32_t
Random::genrand(uint32_t max)
void
Random::init(uint32_t s)
{
if (max == 0)
return 0;
if (max == std::numeric_limits<uint32_t>::max())
return genrand();
int log = ceilLog2(max + 1);
int shift = (sizeof(uint32_t) * 8 - log);
uint32_t random;
do {
random = genrand() >> shift;
} while (random > max);
return random;
}
uint64_t
Random::genrand(uint64_t max)
{
if (max == 0)
return 0;
if (max == std::numeric_limits<uint64_t>::max())
return genrand();
int log = ceilLog2(max + 1);
int shift = (sizeof(uint64_t) * 8 - log);
uint64_t random;
do {
random = (uint64_t)genrand() << 32 | (uint64_t)genrand();
random = random >> shift;
} while (random > max);
return random;
gen.seed(s);
}
void
Random::serialize(const string &base, ostream &os)
Random::serialize(std::ostream &os)
{
int length = N;
paramOut(os, base + ".mti", mti);
paramOut(os, base + ".length", length);
arrayParamOut(os, base + ".data", mt, length);
panic("Currently not used anywhere.\n");
// get the state from the generator
std::ostringstream oss;
oss << gen;
std::string state = oss.str();
paramOut(os, "mt_state", state);
}
void
Random::unserialize(const string &base, Checkpoint *cp, const string &section)
Random::unserialize(Checkpoint *cp, const std::string &section)
{
int length;
panic("Currently not used anywhere.\n");
paramIn(cp, section, base + ".mti", mti);
paramIn(cp, section, base + ".length", length);
if (length != N)
panic("cant unserialize random number data. length != %d\n", length);
arrayParamIn(cp, section, base + ".data", mt, length);
// the random generator state did not use to be part of the
// checkpoint state, so be forgiving in the unserialization and
// keep on going if the parameter is not there
std::string state;
if (optParamIn(cp, section, "mt_state", state)) {
std::istringstream iss(state);
iss >> gen;
}
}
Random random_mt;

View file

@ -1,4 +1,16 @@
/*
* Copyright (c) 2014 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
@ -27,20 +39,19 @@
*
* Authors: Nathan Binkert
* Ali Saidi
* Andreas Hansson
*/
/*
* Mersenne Twister random number generator has a period of
* 2^19937-1.
*
* The actual math is in its own file to keep the license clear.
* Mersenne twister random number generator.
*/
#ifndef __BASE_RANDOM_HH__
#define __BASE_RANDOM_HH__
#include <ios>
#include <random>
#include <string>
#include <type_traits>
#include "base/types.hh"
@ -48,192 +59,51 @@ class Checkpoint;
class Random
{
protected:
static const int N = 624;
static const int M = 397;
static const uint32_t MATRIX_A = (uint32_t)0x9908b0df;
static const uint32_t UPPER_MASK = (uint32_t)0x80000000;
static const uint32_t LOWER_MASK = (uint32_t)0x7fffffff;
uint32_t mt[N];
int mti;
private:
uint32_t genrand();
uint32_t genrand(uint32_t max);
uint64_t genrand(uint64_t max);
void
_random(int8_t &value)
{
value = genrand() & (int8_t)-1;
}
void
_random(int16_t &value)
{
value = genrand() & (int16_t)-1;
}
void
_random(int32_t &value)
{
value = (int32_t)genrand();
}
void
_random(int64_t &value)
{
value = (int64_t)genrand() << 32 | (int64_t)genrand();
}
void
_random(uint8_t &value)
{
value = genrand() & (uint8_t)-1;
}
void
_random(uint16_t &value)
{
value = genrand() & (uint16_t)-1;
}
void
_random(uint32_t &value)
{
value = genrand();
}
void
_random(uint64_t &value)
{
value = (uint64_t)genrand() << 32 | (uint64_t)genrand();
}
// [0,1]
void
_random(float &value)
{
// ieee floats have 23 bits of mantissa
value = (genrand() >> 9) / 8388608.0;
}
// [0,1]
void
_random(double &value)
{
double number = genrand() * 2097152.0 + (genrand() >> 11);
value = number / 9007199254740992.0;
}
// Range based versions of the random number generator
int8_t
_random(int8_t min, int8_t max)
{
uint32_t diff = max - min;
return static_cast<int8_t>(min + genrand(diff));
}
int16_t
_random(int16_t min, int16_t max)
{
uint32_t diff = max - min;
return static_cast<int16_t>(min + genrand(diff));
}
int32_t
_random(int32_t min, int32_t max)
{
uint32_t diff = max - min;
return static_cast<int32_t>(min + genrand(diff));
}
int64_t
_random(int64_t min, int64_t max)
{
uint64_t diff = max - min;
return static_cast<int64_t>(min + genrand(diff));
}
uint8_t
_random(uint8_t min, uint8_t max)
{
uint32_t diff = max - min;
return static_cast<uint8_t>(min + genrand(diff));
}
uint16_t
_random(uint16_t min, uint16_t max)
{
uint32_t diff = max - min;
return static_cast<uint16_t>(min + genrand(diff));
}
uint32_t
_random(uint32_t min, uint32_t max)
{
uint32_t diff = max - min;
return static_cast<uint32_t>(min + genrand(diff));
}
uint64_t
_random(uint64_t min, uint64_t max)
{
uint64_t diff = max - min;
return static_cast<uint64_t>(min + genrand(diff));
}
std::mt19937_64 gen;
public:
Random();
Random(uint32_t s);
Random(uint32_t init_key[], int key_length);
~Random();
void init(uint32_t s);
void init(uint32_t init_key[], int key_length);
/**
* Use the SFINAE idiom to choose an implementation based on
* whether the type is integral or floating point.
*/
template <typename T>
T
typename std::enable_if<std::is_integral<T>::value, T>::type
random()
{
T value;
_random(value);
return value;
// [0, max_value] for integer types
std::uniform_int_distribution<T> dist;
return dist(gen);
}
template <typename T>
T
typename std::enable_if<std::is_floating_point<T>::value, T>::type
random()
{
// [0, 1) for real types
std::uniform_real_distribution<T> dist;
return dist(gen);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
random(T min, T max)
{
return _random(min, max);
std::uniform_int_distribution<T> dist(min, max);
return dist(gen);
}
// [0,1]
double
gen_real1()
{
return genrand() / 4294967296.0;
}
// [0,1)
double
gen_real2()
{
return genrand() / 4294967295.0;
}
// (0,1)
double
gen_real3()
{
return ((double)genrand() + 0.5) / 4294967296.0;
}
public:
void serialize(const std::string &base, std::ostream &os);
void unserialize(const std::string &base, Checkpoint *cp,
const std::string &section);
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
};
extern Random random_mt;

View file

@ -1,149 +0,0 @@
/*
* A C-program for MT19937, with initialization improved 2002/1/26.
* Coded by Takuji Nishimura and Makoto Matsumoto.
*
* Before using, initialize the state by using init_genrand(seed)
* or init_by_array(init_key, key_length).
*
* Copyright (C) 1997-2002 Makoto Matsumoto and Takuji Nishimura
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. The names of its contributors may not be used to endorse or
* promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Any feedback is very welcome.
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
* email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
*/
#include "base/random.hh"
/* initializes mt[N] with a seed */
void
Random::init(uint32_t s)
{
mti = N + 1;
mt[0] = s & (uint32_t)0xffffffff;
for (mti = 1; mti < N; mti++) {
mt[mti] = 1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti;
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= (uint32_t)0xffffffff;
/* for >32 bit machines */
}
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
void
Random::init(uint32_t init_key[], int key_length)
{
int i = 1;
int j = 0;
int k = (N > key_length) ? N : key_length;
init(19650218);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * (uint32_t)1664525))
+ init_key[j] + j; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
j++;
if (i >= N) {
mt[0] = mt[N - 1];
i = 1;
}
if (j >= key_length)
j = 0;
}
for (k = N - 1; k; k--) {
/* non linear */
mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941UL)) - i;
/* for WORDSIZE > 32 machines */
mt[i] &= (uint32_t)0xffffffff;
i++;
if (i >= N) {
mt[0] = mt[N - 1];
i = 1;
}
}
/* MSB is 1; assuring non-zero initial array */
mt[0] = (uint32_t)0x80000000;
}
/* generates a random number on [0,0xffffffff]-interval */
uint32_t
Random::genrand()
{
uint32_t y;
static uint32_t mag01[2] = { 0, MATRIX_A};
if (mti >= N) { /* generate N words at one time */
int kk;
for (kk = 0; kk < N - M; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (; kk < N - 1; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & (uint32_t)0x9d2c5680;
y ^= (y << 15) & (uint32_t)0xefc60000;
y ^= (y >> 18);
return y;
}