Skip to content

Commit

Permalink
use lower order bits in prng
Browse files Browse the repository at this point in the history
- This is about 2 times faster compared to the previous rng.
- Add unit tests to ensure things are correct
- Update integration test data
  • Loading branch information
Soeren Sonnenburg committed May 22, 2013
1 parent 8bb3fd5 commit a2519cf
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 49 deletions.
1 change: 0 additions & 1 deletion src/shogun/lib/Cache.h
Expand Up @@ -165,7 +165,6 @@ template<class T> class CCache : public CSGObject
if (lookup_table)
{
// first look for the element with smallest usage count
//int64_t min_idx=((nr_cache_lines-1)*random())/(RAND_MAX+1); //avoid the last elem and the scratch line
int64_t min_idx=0;
int64_t min=-1;
bool found_free_line=false;
Expand Down
6 changes: 0 additions & 6 deletions src/shogun/lib/common.h
Expand Up @@ -19,12 +19,6 @@
#include <stdio.h>
#include <shogun/lib/config.h>

#ifndef LINUX
#define RANDOM_MAX 2147483647
#else
#define RANDOM_MAX RAND_MAX
#endif

/**@name Standard Types
* Definition of Platform independent Types
*/
Expand Down
38 changes: 8 additions & 30 deletions src/shogun/mathematics/Math.h
Expand Up @@ -461,64 +461,42 @@ class CMath : public CSGObject

static inline uint64_t random()
{
uint64_t rnd = sg_rand->random_64();

return rnd;
return sg_rand->random_64();
}

static inline uint64_t random(uint64_t min_value, uint64_t max_value)
{
uint64_t ret = min_value + (uint64_t) ((max_value-min_value+1) * (CMath::random() / (RAND_MAX_64)));
ASSERT(ret>=min_value && ret<=max_value)
return ret ;
return sg_rand->random(min_value, max_value);
}

static inline int64_t random(int64_t min_value, int64_t max_value)
{
int64_t ret = min_value + (int64_t) ((max_value-min_value+1) * (CMath::random() / (RAND_MAX_64)));
ASSERT(ret>=min_value && ret<=max_value)
return ret ;
return sg_rand->random(min_value, max_value);
}

static inline uint32_t random(uint32_t min_value, uint32_t max_value)
{
uint32_t ret = min_value + (uint32_t) ((max_value-min_value+1) * (CMath::random() / (RAND_MAX_64)));
ASSERT(ret>=min_value && ret<=max_value)
return ret ;
return sg_rand->random(min_value, max_value);
}

static inline int32_t random(int32_t min_value, int32_t max_value)
{
int32_t ret = min_value + (int32_t) ((max_value-min_value+1) * (CMath::random() / (RAND_MAX_64)));
ASSERT(ret>=min_value && ret<=max_value)
return ret ;
return sg_rand->random(min_value, max_value);
}

static inline float32_t random(float32_t min_value, float32_t max_value)
{
float32_t ret = min_value + ((max_value-min_value) * sg_rand->random_close());
if (ret<min_value || ret>max_value)
SG_SPRINT("min_value:%10.10f value: %10.10f max_value:%10.10f", min_value, ret, max_value)
ASSERT(ret>=min_value && ret<=max_value)
return ret;
return sg_rand->random(min_value, max_value);
}

static inline float64_t random(float64_t min_value, float64_t max_value)
{
float64_t ret = min_value + ((max_value-min_value) * sg_rand->random_close());
if (ret<min_value || ret>max_value)
SG_SPRINT("min_value:%10.10f value: %10.10f max_value:%10.10f", min_value, ret, max_value)
ASSERT(ret>=min_value && ret<=max_value)
return ret;
return sg_rand->random(min_value, max_value);
}

static inline floatmax_t random(floatmax_t min_value, floatmax_t max_value)
{
floatmax_t ret = min_value + ((max_value-min_value) * sg_rand->random_close());
if (ret<min_value || ret>max_value)
SG_SPRINT("min_value:%10.10f value: %10.10f max_value:%10.10f", min_value, ret, max_value)
ASSERT(ret>=min_value && ret<=max_value)
return ret;
return sg_rand->random(min_value, max_value);
}

/// Returns a Gaussian or Normal random number.
Expand Down
62 changes: 57 additions & 5 deletions src/shogun/mathematics/Random.h
Expand Up @@ -18,9 +18,6 @@
#include <shogun/lib/external/SFMT/SFMT.h>
#include <shogun/lib/external/dSFMT/dSFMT.h>

#define RAND_MAX_32 ((float32_t)std::numeric_limits<uint32_t>::max())
#define RAND_MAX_64 ((float64_t)std::numeric_limits<uint64_t>::max())

namespace shogun
{
/** @brief: Pseudo random number geneartor
Expand Down Expand Up @@ -56,19 +53,74 @@ namespace shogun
uint32_t get_seed() const;

/**
* Generate an unsinged 32-bit random integer
* Generate an unsigned 32-bit random integer
*
* @return the random 32-bit unsigned integer
*/
uint32_t random_32() const;

/**
* Generate an unsinged 64-bit random integer
* Generate an unsigned 64-bit random integer
*
* @return the random 64-bit unsigned integer
*/
uint64_t random_64() const;

/**
* Generate a signed 32-bit random integer
*
* @return the random 32-bit signed integer
*/
inline int32_t random_s32() const
{
return random_32() & 0x7fffffff;
}

/**
* Generate a signed 64-bit random integer
*
* @return the random 64-bit signed integer
*/
int64_t random_s64() const
{
return random_64() & 0x7fffffffffffffffl;
}

inline uint64_t random(uint64_t min_value, uint64_t max_value)
{
return min_value + random_64() % (max_value-min_value+1);
}

inline int64_t random(int64_t min_value, int64_t max_value)
{
return min_value + random_s64() % (max_value-min_value+1);
}

inline uint32_t random(uint32_t min_value, uint32_t max_value)
{
return min_value + random_32() % (max_value-min_value+1);
}

inline int32_t random(int32_t min_value, int32_t max_value)
{
return min_value + random_s32() % (max_value-min_value+1);
}

inline float32_t random(float32_t min_value, float32_t max_value)
{
return min_value + ((max_value-min_value) * random_close());
}

inline float64_t random(float64_t min_value, float64_t max_value)
{
return min_value + ((max_value-min_value) * random_close());
}

inline floatmax_t random(floatmax_t min_value, floatmax_t max_value)
{
return min_value + ((max_value-min_value) * random_close());
}

/**
* Fill an array of unsinged 32 bit integer
*
Expand Down
126 changes: 120 additions & 6 deletions tests/unit/mathematics/Random_unittest.cc
Expand Up @@ -3,9 +3,13 @@
#include <shogun/mathematics/Math.h>
#include <shogun/lib/SGVector.h>
#include <gtest/gtest.h>
#include <stdio.h>

using namespace shogun;

const uint32_t n_runs=1200000;
const uint32_t array_len=23;

/**
* NOTE: these unit tests were generated with MEXP=19937
* with other exponents it is expected to fail!
Expand Down Expand Up @@ -193,17 +197,127 @@ TEST(Random, random_int32_1_2)
}
}

TEST(Random, random_int32_0_10)
TEST(Random, random_int64_range)
{
CMath::init_random(17);
int rnds[10] = {0,0,0,0,0,0};
for (int32_t i=0; i<10000; i++)
int rnds[array_len];
for (uint32_t i=0; i<array_len; i++)
rnds[i]=0;
for (uint32_t i=0; i<n_runs; i++)
{
int32_t r=CMath::random((int32_t) 0, (int32_t) 9);
int64_t r=CMath::random((int64_t) 0, (int64_t) array_len-1);
rnds[r]++;
}

for (int32_t i=0; i<10; i++) {
EXPECT_TRUE(rnds[i]>0);
for (uint32_t i=0; i<array_len; i++) {
double pbin=double(rnds[i])/n_runs*100*array_len;
EXPECT_GE(pbin, 99.0);
}
}

TEST(Random, random_uint64_range)
{
CMath::init_random(17);
int rnds[array_len];
for (uint32_t i=0; i<array_len; i++)
rnds[i]=0;
for (uint32_t i=0; i<n_runs; i++)
{
uint64_t r=CMath::random((uint64_t) 0, (uint64_t) array_len-1);
rnds[r]++;
}

for (uint32_t i=0; i<array_len; i++) {
double pbin=double(rnds[i])/n_runs*100*array_len;
EXPECT_GE(pbin, 99.0);
}
}

TEST(Random, random_int32_range)
{
CMath::init_random(17);
int rnds[array_len];
for (uint32_t i=0; i<array_len; i++)
rnds[i]=0;
for (uint32_t i=0; i<n_runs; i++)
{
int32_t r=CMath::random((int32_t) 0, (int32_t) array_len-1);
rnds[r]++;
}

for (uint32_t i=0; i<array_len; i++) {
double pbin=double(rnds[i])/n_runs*100*array_len;
EXPECT_GE(pbin, 99.0);
}
}

TEST(Random, random_uint32_range)
{
CMath::init_random(17);
int rnds[array_len];
for (uint32_t i=0; i<array_len; i++)
rnds[i]=0;
for (uint32_t i=0; i<n_runs; i++)
{
uint32_t r=CMath::random((uint32_t) 0, (uint32_t) array_len-1);
rnds[r]++;
}

for (uint32_t i=0; i<array_len; i++) {
double pbin=double(rnds[i])/n_runs*100*array_len;
EXPECT_GE(pbin, 99.0);
}
}

TEST(Random, random_uint32_random_range)
{
CRandom* prng = new CRandom();
prng->set_seed(17);
int rnds[array_len];
for (uint32_t i=0; i<array_len; i++)
rnds[i]=0;
for (uint32_t i=0; i<n_runs; i++)
{
uint32_t r=prng->random_32() % array_len;
rnds[r]++;
}

for (uint32_t i=0; i<array_len; i++) {
double pbin=double(rnds[i])/n_runs*100*array_len;
EXPECT_GE(pbin, 99.0);
}
SG_UNREF(prng);
}

TEST(Random, random_float64_range)
{
CMath::init_random(17);
int rnds[array_len];
for (uint32_t i=0; i<array_len; i++)
rnds[i]=0;
for (uint32_t i=0; i<n_runs; i++)
{
int32_t r= (int32_t) CMath::random((float64_t) 0, (float64_t) array_len);
rnds[r]++;
}

for (uint32_t i=0; i<array_len; i++) {
double pbin=double(rnds[i])/n_runs*100*array_len;
EXPECT_GE(pbin, 99.0);
}
}

TEST(Random, random_float64_range2)
{
CMath::init_random(12345678);
float64_t min=1.0;
float64_t max=0.0;
for (uint32_t i=0; i<n_runs; i++)
{
float64_t r=CMath::random((float64_t) 0, (float64_t) 1.0);
min=CMath::min(min, r);
max=CMath::max(max, r);
}
EXPECT_GE(max, 0.99999);
EXPECT_LE(min, 0.00001);
}

0 comments on commit a2519cf

Please sign in to comment.