diff --git a/src/base/SConscript b/src/base/SConscript index 0bb0cb0fb..e7c420f78 100644 --- a/src/base/SConscript +++ b/src/base/SConscript @@ -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') diff --git a/src/base/random.cc b/src/base/random.cc index cffeddec9..ced9a8f45 100644 --- a/src/base/random.cc +++ b/src/base/random.cc @@ -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 -#include "base/fenv.hh" -#include "base/intmath.hh" +#include + #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::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::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 §ion) +Random::unserialize(Checkpoint *cp, const std::string §ion) { - 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; diff --git a/src/base/random.hh b/src/base/random.hh index 34107c76f..cedbd6bd4 100644 --- a/src/base/random.hh +++ b/src/base/random.hh @@ -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 +#include #include +#include #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(min + genrand(diff)); - } - - int16_t - _random(int16_t min, int16_t max) - { - uint32_t diff = max - min; - return static_cast(min + genrand(diff)); - } - - int32_t - _random(int32_t min, int32_t max) - { - uint32_t diff = max - min; - return static_cast(min + genrand(diff)); - } - - int64_t - _random(int64_t min, int64_t max) - { - uint64_t diff = max - min; - return static_cast(min + genrand(diff)); - } - - uint8_t - _random(uint8_t min, uint8_t max) - { - uint32_t diff = max - min; - return static_cast(min + genrand(diff)); - } - - uint16_t - _random(uint16_t min, uint16_t max) - { - uint32_t diff = max - min; - return static_cast(min + genrand(diff)); - } - - uint32_t - _random(uint32_t min, uint32_t max) - { - uint32_t diff = max - min; - return static_cast(min + genrand(diff)); - } - - uint64_t - _random(uint64_t min, uint64_t max) - { - uint64_t diff = max - min; - return static_cast(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 - T + typename std::enable_if::value, T>::type random() { - T value; - _random(value); - return value; + // [0, max_value] for integer types + std::uniform_int_distribution dist; + return dist(gen); } template - T + typename std::enable_if::value, T>::type + random() + { + // [0, 1) for real types + std::uniform_real_distribution dist; + return dist(gen); + } + + template + typename std::enable_if::value, T>::type random(T min, T max) { - return _random(min, max); + std::uniform_int_distribution 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 §ion); + void serialize(std::ostream &os); + void unserialize(Checkpoint *cp, const std::string §ion); }; extern Random random_mt; diff --git a/src/base/random_mt.cc b/src/base/random_mt.cc deleted file mode 100644 index 70a7b0436..000000000 --- a/src/base/random_mt.cc +++ /dev/null @@ -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; -}