stats: cleanup a few small problems in stats
[gem5.git] / src / base / random.cc
index 0ccedcb00ac9d83182fc1c3034ae4576ef9ea7dc..7daa90b9cf98ed22757cc0a153dc239790c5d341 100644 (file)
  *          Ali Saidi
  */
 
-#if defined(__sun)
-#include <ieeefp.h>
-#endif
-#ifdef __SUNPRO_CC
-#include <stdlib.h>
-#include <math.h>
-#endif
-
-#include <cstdlib>
-#include <cmath>
-
-
-#include "sim/param.hh"
+#include "base/fenv.hh"
+#include "base/intmath.hh"
+#include "base/misc.hh"
 #include "base/random.hh"
-#include "base/trace.hh"
+#include "sim/serialize.hh"
 
 using namespace std;
 
-class RandomContext : public ParamContext
+Random::Random()
 {
-  public:
-    RandomContext(const string &_iniSection)
-        : ::ParamContext(_iniSection) {}
-    ~RandomContext() {}
-
-    void checkParams();
-};
-
-RandomContext paramContext("random");
-
-Param<unsigned>
-seed(&paramContext, "seed", "seed to random number generator", 1);
+    // default random seed taken from original source
+    init(5489);
+}
 
-void
-RandomContext::checkParams()
+Random::Random(uint32_t s)
 {
-    ::srand48(seed);
+    init(s);
 }
 
-long
-getLong()
+Random::Random(uint32_t init_key[], int key_length)
 {
-    return mrand48();
+    init(init_key, key_length);
 }
 
-double
-m5round(double r)
+Random::~Random()
 {
-#if defined(__sun)
-    double val;
-    fp_rnd oldrnd = fpsetround(FP_RN);
-    val = rint(r);
-    fpsetround(oldrnd);
-    return val;
-#else
-    return round(r);
-#endif
 }
 
-int64_t
-getUniform(int64_t min, int64_t max)
+// 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)
 {
-    double r;
-    r = drand48() * (max-min) + min;
+    int log = ceilLog2(max);
+    int shift = (sizeof(uint32_t) * 8 - log);
+    uint32_t random;
 
-    return (int64_t)m5round(r);
+    do {
+        random = genrand() >> shift;
+    } while (random > max);
+
+    return random;
 }
 
 uint64_t
-getUniformPos(uint64_t min, uint64_t max)
+Random::genrand(uint64_t max)
 {
-    double r;
-    r = drand48() * (max-min) + min;
+    int log = ceilLog2(max);
+    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 (uint64_t)m5round(r);
+    return random;
 }
 
+void
+Random::serialize(const string &base, ostream &os)
+{
+    int length = N;
+    paramOut(os, base + ".mti", mti);
+    paramOut(os, base + ".length", length);
+    arrayParamOut(os, base + ".data", mt, length);
+}
 
-// idea for generating a double from erand48
-double
-getDouble()
+void
+Random::unserialize(const string &base, Checkpoint *cp, const string &section)
 {
-    union {
-        uint32_t _long[2];
-        uint16_t _short[4];
-    };
+    int length;
 
-    _long[0] = mrand48();
-    _long[1] = mrand48();
+    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);
 
-    return ldexp((double) _short[0], -48) +
-        ldexp((double) _short[1], -32) +
-        ldexp((double) _short[2], -16);
+    arrayParamIn(cp, section, base + ".data", mt, length);
 }
+
+Random random_mt;