This commit is contained in:
Matthias Huck 2015-04-23 18:14:40 +01:00
commit bbcc8bf23b
24 changed files with 452 additions and 117 deletions

View File

@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "moses/Word.h"
#include "moses/FF/FeatureFunction.h"
#include "Decoder.h"
#include "util/random.hh"
typedef std::map<const Moses::FeatureFunction*, std::vector< float > > ProducerWeightMap;
typedef std::pair<const Moses::FeatureFunction*, std::vector< float > > ProducerWeightPair;
@ -37,8 +38,11 @@ template <class T> bool from_string(T& t, const std::string& s, std::ios_base& (
struct RandomIndex {
ptrdiff_t operator()(ptrdiff_t max) {
srand(time(0)); // Initialize random number generator with current time.
return static_cast<ptrdiff_t> (rand() % max);
// TODO: Don't seed the randomizer here. If this function gets called
// multiple times in the same second, it will return the same value on
// each of those calls.
util::rand_init();
return util::rand_excl(max);
}
};

View File

@ -42,6 +42,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "RelativeEntropyCalc.h"
#include "LexicalReordering.h"
#include "LexicalReorderingState.h"
#include "util/random.hh"
#ifdef HAVE_PROTOBUF
#include "hypergraph.pb.h"
@ -205,7 +206,7 @@ int main(int argc, char** argv)
//initialise random numbers
srand(time(NULL));
rand_init();
// set up read/writing class
IOWrapper* ioWrapper = GetIOWrapper(staticData);

View File

@ -287,7 +287,7 @@ void Data::createShards(size_t shard_count, float shard_size, const string& scor
} else {
//create shards by randomly sampling
for (size_t i = 0; i < floor(shard_size+0.5); ++i) {
shard_contents.push_back(util::rand_int() % data_size);
shard_contents.push_back(util::rand_excl(data_size));
}
}

View File

@ -58,10 +58,8 @@ void Point::Randomize()
UTIL_THROW_IF(m_min.size() != Point::m_dim, util::Exception, "Error");
UTIL_THROW_IF(m_max.size() != Point::m_dim, util::Exception, "Error");
for (unsigned int i = 0; i < size(); i++) {
const float scale = (m_max[i] - m_min[i]) / float(RAND_MAX);
operator[](i) = m_min[i] + util::rand_int() * scale;
}
for (unsigned int i = 0; i < size(); i++)
operator[](i) = util::rand_incl(m_min[i], m_max[i]);
}
double Point::operator*(const FeatureStats& F) const

View File

@ -5,11 +5,8 @@
- check that --pairwise-ranked is compatible with all optimization metrics
- Replace the standard rand() currently used in MERT and PRO with better
random generators such as Boost's random generators (e.g., boost::mt19937).
- create a Random class to hide the details, i.e., how to generate
random numbers, which allows us to use custom random generators more
easily.
- Use better random generators in util/random.cc, e.g. boost::mt19937.
- Support plugging of custom random generators.
Pros:
- In MERT, you might want to use the random restarting technique to avoid

View File

@ -95,7 +95,7 @@ void EvaluatorUtil::evaluate(const string& candFile, int bootstrap, bool nbest_i
for (int i = 0; i < bootstrap; ++i) {
ScoreData scoredata(g_scorer);
for (int j = 0; j < n; ++j) {
int randomIndex = util::rand_int() % n;
const int randomIndex = util::rand_excl(n);
scoredata.add(entries[randomIndex], j);
}
g_scorer->setScoreData(&scoredata);
@ -285,10 +285,10 @@ void InitSeed(const ProgramOption *opt)
{
if (opt->has_seed) {
cerr << "Seeding random numbers with " << opt->seed << endl;
util::rand_int_init(opt->seed);
util::rand_init(opt->seed);
} else {
cerr << "Seeding random numbers with system clock " << endl;
util::rand_int_init();
util::rand_init();
}
}

View File

@ -40,6 +40,7 @@ de recherches du Canada
#include <boost/scoped_ptr.hpp>
#include "util/exception.hh"
#include "util/random.hh"
#include "BleuScorer.h"
#include "HopeFearDecoder.h"
@ -122,10 +123,10 @@ int main(int argc, char** argv)
if (vm.count("random-seed")) {
cerr << "Initialising random seed to " << seed << endl;
srand(seed);
util::rand_init(seed);
} else {
cerr << "Initialising random seed from system clock" << endl;
srand(time(NULL));
util::rand_init();
}
// Initialize weights

View File

@ -290,10 +290,10 @@ int main(int argc, char **argv)
if (option.has_seed) {
cerr << "Seeding random numbers with " << option.seed << endl;
util::rand_int_init(option.seed);
util::rand_init(option.seed);
} else {
cerr << "Seeding random numbers with system clock " << endl;
util::rand_int_init();
util::rand_init();
}
if (option.sparse_weights_file.size()) ++option.pdim;

View File

@ -43,6 +43,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ScoreDataIterator.h"
#include "BleuScorer.h"
#include "Util.h"
#include "util/random.hh"
using namespace std;
using namespace MosesTuning;
@ -141,10 +142,10 @@ int main(int argc, char** argv)
if (vm.count("random-seed")) {
cerr << "Initialising random seed to " << seed << endl;
srand(seed);
util::rand_init(seed);
} else {
cerr << "Initialising random seed from system clock" << endl;
srand(time(NULL));
util::rand_init();
}
if (scoreFiles.size() == 0 || featureFiles.size() == 0) {
@ -211,11 +212,11 @@ int main(int argc, char** argv)
vector<float> scores;
size_t n_translations = hypotheses.size();
for(size_t i=0; i<n_candidates; i++) {
size_t rand1 = rand() % n_translations;
size_t rand1 = util::rand_excl(n_translations);
pair<size_t,size_t> translation1 = hypotheses[rand1];
float bleu1 = smoothedSentenceBleu(scoreDataIters[translation1.first]->operator[](translation1.second), bleuSmoothing, smoothBP);
size_t rand2 = rand() % n_translations;
size_t rand2 = util::rand_excl(n_translations);
pair<size_t,size_t> translation2 = hypotheses[rand2];
float bleu2 = smoothedSentenceBleu(scoreDataIters[translation2.first]->operator[](translation2.second), bleuSmoothing, smoothBP);

View File

@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "moses/FF/StatefulFeatureFunction.h"
#include "moses/FF/StatelessFeatureFunction.h"
#include "moses/TrainingTask.h"
#include "util/random.hh"
#ifdef HAVE_PROTOBUF
#include "hypergraph.pb.h"
@ -117,7 +118,7 @@ int main(int argc, char** argv)
//initialise random numbers
srand(time(NULL));
util::rand_init();
// set up read/writing class
IFVERBOSE(1) {

View File

@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include <sstream>
#include <vector>
#include "util/random.hh"
#include "util/usage.hh"
#ifdef WIN32
@ -91,7 +92,7 @@ SimpleTranslationInterface::SimpleTranslationInterface(const string &mosesIni):
exit(1);
}
srand(time(NULL));
util::rand_init();
}
@ -185,7 +186,7 @@ batch_run()
const StaticData& staticData = StaticData::Instance();
//initialise random numbers
srand(time(NULL));
util::rand_init();
IFVERBOSE(1) PrintUserTime("Created input-output object");

View File

@ -54,6 +54,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#include "util/exception.hh"
#include "util/random.hh"
using namespace std;
@ -418,7 +419,7 @@ void Manager::CalcLatticeSamples(size_t count, TrellisPathList &ret) const
//cerr << endl;
//draw the sample
float frandom = log((float)rand()/RAND_MAX);
const float frandom = log(util::rand_incl(0.0f, 1.0f));
size_t position = 1;
float sum = candidateScores[0];
for (; position < candidateScores.size() && sum < frandom; ++position) {

View File

@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "InputFileStream.h"
#include "StaticData.h"
#include "util/exception.hh"
#include "util/random.hh"
#include <boost/program_options.hpp>
@ -1392,7 +1393,7 @@ struct Credit {
this->contact = contact ;
this->currentPursuits = currentPursuits ;
this->areaResponsibility = areaResponsibility;
this->sortId = rand() % 1000;
this->sortId = util::rand_excl(1000);
}
bool operator<(const Credit &other) const {

View File

@ -6,6 +6,7 @@
#include "utils.h"
#include "FileHandler.h"
#include "util/exception.hh"
#include "util/random.hh"
using namespace Moses;
typedef uint64_t P; // largest input range is 2^64
@ -162,7 +163,7 @@ void Hash_shiftAddXOR<T>::initSeeds()
{
v_ = new T[this->H_];
for(count_t i=0; i < this->H_; i++)
v_[i] = Utils::rand<T>() + 1;
v_[i] = util::wide_rand<T>() + 1;
}
template <typename T>
T Hash_shiftAddXOR<T>::hash(const char* s, count_t h)
@ -187,9 +188,8 @@ void UnivHash_tableXOR<T>::initSeeds()
// fill with random values
for(count_t j=0; j < this->H_; j++) {
table_[j] = new T[tblLen_];
for(count_t i=0; i < tblLen_; i++) {
table_[j][i] = Utils::rand<T>(this->m_-1);
}
for(count_t i=0; i < tblLen_; i++)
table_[j][i] = util::wide_rand_excl(this->m_-1);
}
}
template <typename T>
@ -218,7 +218,7 @@ void UnivHash_noPrimes<T>::initSeeds()
{
a_ = new P[this->H_];
for(T i=0; i < this->H_; i++) {
a_[i] = Utils::rand<P>();
a_[i] = util::wide_rand<P>();
if(a_[i] % 2 == 0) a_[i]++; // a must be odd
}
}
@ -284,8 +284,8 @@ void UnivHash_linear<T>::initSeeds()
a_[i] = new T[MAX_NGRAM_ORDER];
b_[i] = new T[MAX_NGRAM_ORDER];
for(count_t j=0; j < MAX_NGRAM_ORDER; j++) {
a_[i][j] = 1 + Utils::rand<T>();
b_[i][j] = Utils::rand<T>();
a_[i][j] = 1 + util::wide_rand<T>();
b_[i][j] = util::wide_rand<T>();
}
}
}

View File

@ -62,22 +62,6 @@ public:
str[i] = tolower(str[i]);
}
}
// TODO: interface with decent PRG
template<typename T>
static T rand(T mod_bnd = 0) {
T random = 0;
if(sizeof(T) <= 4) {
random = static_cast<T>(std::rand());
} else if(sizeof(T) == 8) {
random = static_cast<T>(std::rand());
random <<= 31;
random <<= 1;
random |= static_cast<T>(std::rand());
}
if(mod_bnd != 0)
return random % mod_bnd;
else return random;
}
};
#endif

View File

@ -1,4 +1,6 @@
#include "DynSuffixArray.h"
#include "util/random.hh"
#include <iostream>
#include <boost/foreach.hpp>
@ -315,33 +317,31 @@ int DynSuffixArray::Compare(int pos1, int pos2, int max)
return 0;
}
namespace
{
/// Helper: swap two entries in an int array.
inline void swap_ints(int array[], int one, int other)
{
const int tmp = array[one];
array[one] = array[other];
array[other] = tmp;
}
}
void DynSuffixArray::Qsort(int* array, int begin, int end)
{
if(end > begin) {
int index;
int index = util::rand_incl(begin, end);
{
index = begin + (rand() % (end - begin + 1));
int pivot = array[index];
{
int tmp = array[index];
array[index] = array[end];
array[end] = tmp;
}
const int pivot = array[index];
swap_ints(array, index, end);
for(int i=index=begin; i < end; ++i) {
if (Compare(array[i], pivot, 20) <= 0) {
{
int tmp = array[index];
array[index] = array[i];
array[i] = tmp;
index++;
}
swap_ints(array, index, i);
index++;
}
}
{
int tmp = array[index];
array[index] = array[end];
array[end] = tmp;
}
swap_ints(array, index, end);
}
Qsort(array, begin, index - 1);
Qsort(array, index + 1, end);

View File

@ -45,6 +45,7 @@
#include "moses/TranslationModel/fuzzy-match/SentenceAlignment.h"
#include "util/file.hh"
#include "util/exception.hh"
#include "util/random.hh"
using namespace std;
@ -62,8 +63,8 @@ char *mkdtemp(char *tempbuf)
return NULL;
}
srand((unsigned)time(0));
rand_value = (int)((rand() / ((double)RAND_MAX+1.0)) * 1e6);
util::rand_init();
rand_value = rand_excl(1e6);
tempbase = strrchr(tempbuf, '/');
tempbase = tempbase ? tempbase+1 : tempbuf;
strcpy(tempbasebuf, tempbase);

View File

@ -2,19 +2,16 @@
#define __sampling_h
#include <boost/dynamic_bitset.hpp>
#include <vector>
#include "util/random.hh"
// Utility functions for proper sub-sampling.
// (c) 2007-2012 Ulrich Germann
namespace Moses
{
using namespace std;
inline
size_t
randInt(size_t N)
{
return N*(rand()/(RAND_MAX+1.));
}
using namespace std;
// select a random sample of size /s/ without restitution from the range of
// integers [0,N);
@ -35,15 +32,15 @@ randomSample(vector<idx_t>& v, size_t s, size_t N)
if (s*10<N) {
boost::dynamic_bitset<uint64_t> check(N,0);
for (size_t i = 0; i < v.size(); i++) {
size_t x = randInt(N);
while (check[x]) x = randInt(N);
size_t x = util::rand_excl(N);
while (check[x]) x = util::rand_excl(N);
check[x]=true;
v[i] = x;
}
} else {
size_t m=0;
for (size_t t = 0; m <= s && t < N; t++)
if (s==N || randInt(N-t) < s-m) v[m++] = t;
if (s==N || util::rand_excl(N-t) < s-m) v[m++] = t;
}
}

View File

@ -345,7 +345,7 @@
// {
// boost::lock_guard<boost::mutex> lock(stats->lock);
// if (stats->raw_cnt == ctr) ++stats->raw_cnt;
// size_t rnum = randInt(stats->raw_cnt - ctr++);
// size_t rnum = util::rand_excl(stats->raw_cnt - ctr++);
// // cout << stats->raw_cnt << " " << ctr-1 << " "
// // << rnum << " " << max_samples - stats->good << endl;
// if (rnum < max_samples - stats->good)

View File

@ -69,7 +69,7 @@ namespace ugdiss
// while (chosen < samplesize && next < stop)
// {
// root->readEntry(next,*this);
// if (randInt(N - sampled++) < samplesize - chosen)
// if (util::rand_excl(N - sampled++) < samplesize - chosen)
// {
// ++chosen;
// return true;

View File

@ -9,6 +9,7 @@
#include <iostream>
#include "util/exception.hh"
#include "moses/Util.h"
#include "util/random.hh"
//#include <cassert>
// #include "ug_bv_iter.h"
@ -894,13 +895,6 @@ namespace ugdiss
return bv;
}
inline
size_t
randInt(size_t N)
{
return size_t(N*(rand()/(RAND_MAX+1.)));
}
/// randomly select up to N occurrences of the sequence
template<typename Token>
sptr<vector<typename ttrack::Position> >
@ -922,8 +916,8 @@ namespace ugdiss
root->readEntry(I.next,I);
// t: expected number of remaining samples
double t = (stop - I.pos)/root->aveIndexEntrySize();
double r = t*rand()/(RAND_MAX+1.);
const double t = (stop - I.pos)/root->aveIndexEntrySize();
const double r = util::rand_excl(t);
if (r < N-m)
{
ret->at(m).offset = I.offset;

View File

@ -19,21 +19,25 @@ namespace
boost::mutex rand_lock;
} // namespace
void rand_int_init(unsigned int seed)
void rand_init(unsigned int seed)
{
boost::lock_guard<boost::mutex> lock(rand_lock);
srand(seed);
}
void rand_int_init()
void rand_init()
{
rand_int_init(time(NULL));
rand_init(time(NULL));
}
namespace internal
{
// This is the one call to the actual randomizer. All else is built on this.
int rand_int()
{
boost::lock_guard<boost::mutex> lock(rand_lock);
return rand();
return std::rand();
}
} // namespace internal
} // namespace util

View File

@ -1,32 +1,229 @@
#ifndef UTIL_RANDOM_H
#define UTIL_RANDOM_H
#include <cstdlib>
#include <limits>
namespace util
{
/** Thread-safe, cross-platform random number generator.
*
* This is not for proper security-grade randomness, but should be "good
* enough" for producing arbitrary values of various numeric types.
*
* Before starting, call rand_init() to seed the randomizer. There is no need
* to do this more than once; in fact doing it more often is likely to make the
* randomizer less effective. Once that is done, call the rand(), rand_excl(),
* and rand_incl() functions as needed to generate pseudo-random numbers.
*
* Probability distribution is roughly uniform, but for integral types is
* skewed slightly towards lower numbers depending on how close "top" comes to
* RAND_MAX.
*
* For floating-point types, resolution is limited; there will actually be
* only RAND_MAX different possible values.
*/
/** Initialize randomizer with a fixed seed.
*
* After this, unless the randomizer gets seeded again, consecutive calls to
* rand_int() will return a sequence of pseudo-random numbers determined by
* the seed. Every time the randomizer is seeded with this same seed, it will
* again start returning the same sequence of numbers.
* the random functions will return a sequence of pseudo-random numbers
* determined by the seed. Every time the randomizer is seeded with this same
* seed, it will again start returning the same sequence of numbers.
*/
void rand_int_init(unsigned int);
void rand_init(unsigned int);
/** Initialize randomizer based on current time.
*
* Call this to make the randomizer return hard-to-predict numbers. It won't
* produce high-grade randomness, but enough to make the program act
* differently on different runs.
*
* The seed will be based on the current time in seconds. So calling it twice
* within the same second will just reset the randomizer to where it was before.
* Don't do that.
*/
void rand_int_init();
void rand_init();
/** Return a pseudorandom number between 0 and RAND_MAX inclusive.
*
* Initialize (seed) the randomizer before starting to call this.
*/
template<typename T> inline T rand();
/** Return a pseudorandom number in the half-open interval [bottom, top).
*
* Generates a value between "bottom" (inclusive) and "top" (exclusive),
* assuming that (top - bottom) <= RAND_MAX.
*/
template<typename T> inline T rand_excl(T bottom, T top);
/** Return a pseudorandom number in the half-open interval [0, top).
*
* Generates a value between 0 (inclusive) and "top" (exclusive), assuming that
* bottom <= RAND_MAX.
*/
template<typename T> inline T rand_excl(T top);
/** Return a pseudorandom number in the open interval [bottom, top].
*
* Generates a value between "bottom" and "top" inclusive, assuming that
* (top - bottom) < RAND_MAX.
*/
template<typename T> inline T rand_incl(T bottom, T top);
/** Return a pseudorandom number in the open interval [0, top].
*
* Generates a value between 0 and "top" inclusive, assuming that
* bottom < RAND_MAX.
*/
template<typename T> inline T rand_incl(T top);
/** Return a pseudorandom number which may be larger than RAND_MAX.
*
* The requested type must be integral, and its size must be an even multiple
* of the size of an int. The return value will combine one or more random
* ints into a single value, which could get quite large.
*
* The result is nonnegative. Because the constituent ints are also
* nonnegative, the most significant bit in each of the ints will be zero,
* so for a wider type, there will be "gaps" in the range of possible outputs.
*/
template<typename T> inline T wide_rand();
/** Return a pseudorandom number in [0, top), not limited to RAND_MAX.
*
* Works like wide_rand(), but if the requested type is wider than an int, it
* accommodates larger top values than an int can represent.
*/
template<typename T> inline T wide_rand_excl(T top);
/** Return a pseudorandom number in [bottom, top), not limited to RAND_MAX.
*
* Works like wide_rand(), but if the requested type is wider than an int, it
* accommodates larger value ranges than an int can represent.
*/
template<typename T> inline T wide_rand_excl(T bottom, T top);
/** Return a pseudorandom number in [0, top], not limited to RAND_MAX.
*
* Works like wide_rand(), but if the requested type is wider than an int, it
* accommodates larger top values than an int can represent.
*/
template<typename T> inline T wide_rand_incl(T top);
/** Return a pseudorandom number in [bottom, top], not limited to RAND_MAX.
*
* Works like wide_rand(), but if the requested type is wider than an int, it
* accommodates larger top values than an int can represent.
*/
template<typename T> inline T wide_rand_incl(T bottom, T top);
/// Implementation detail. For the random module's internal use only.
namespace internal
{
/// The central call to the randomizer upon which this whole module is built.
int rand_int();
/// Helper template: customize random values to required ranges.
template<typename T, bool is_integer_type> struct random_scaler;
/// Specialized random_scaler for integral types.
template<typename T> struct random_scaler<T, true>
{
static T rnd_excl(T value, T range) { return value % range; }
static T rnd_incl(T value, T range) { return value % (range + 1); }
};
/// Specialized random_scaler for non-integral types.
template<typename T> struct random_scaler<T, false>
{
static T rnd_excl(T value, T range)
{
// Promote RAND_MAX to T before adding one to avoid overflow.
return range * value / (T(RAND_MAX) + 1);
}
static T rnd_incl(T value, T range) { return range * value / RAND_MAX; }
};
/// Helper for filling a wider variable with random ints.
template<typename T, size_t remaining_ints> struct wide_random_collector
{
static T generate()
{
T one_int = util::rand<T>() << (8 * sizeof(int));
return one_int | wide_random_collector<T, remaining_ints-1>::generate();
}
};
/// Specialized wide_random_collector for generating just a single int.
template<typename T> struct wide_random_collector<T, 1>
{
static T generate() { return util::rand<T>(); }
};
} // namespace internal
template<typename T> inline T rand()
{
return T(util::internal::rand_int());
}
template<typename T> inline T rand_excl(T top)
{
typedef internal::random_scaler<T, std::numeric_limits<T>::is_integer> scaler;
return scaler::rnd_excl(util::rand<T>(), top);
}
template<typename T> inline T rand_excl(T bottom, T top)
{
return bottom + rand_excl(top - bottom);
}
template<typename T> inline T rand_incl(T top)
{
typedef internal::random_scaler<T, std::numeric_limits<T>::is_integer> scaler;
return scaler::rnd_incl(util::rand<T>(), top);
}
template<typename T> inline T rand_incl(T bottom, T top)
{
return bottom + rand_incl(top - bottom);
}
template<typename T> inline T wide_rand()
{
return internal::wide_random_collector<T, sizeof(T)/sizeof(int)>::generate();
}
template<typename T> inline T wide_rand_excl(T top)
{
typedef internal::random_scaler<T, std::numeric_limits<T>::is_integer> scaler;
return scaler::rnd_excl(util::wide_rand<T>(), top);
}
template<typename T> inline T wide_rand_excl(T bottom, T top)
{
return bottom + wide_rand_excl(top - bottom);
}
template<typename T> inline T wide_rand_incl(T top)
{
typedef internal::random_scaler<T, std::numeric_limits<T>::is_integer> scaler;
return scaler::rnd_incl(util::wide_rand<T>(), top);
}
template<typename T> inline T wide_rand_incl(T bottom, T top)
{
return bottom + wide_rand_incl(top - bottom);
}
} // namespace util
#endif

View File

@ -1,3 +1,5 @@
#include <cstdlib>
#include "util/random.hh"
#define BOOST_TEST_MODULE RandomTest
@ -8,32 +10,182 @@ namespace util
namespace
{
BOOST_AUTO_TEST_CASE(returns_different_consecutive_numbers)
BOOST_AUTO_TEST_CASE(rand_int_returns_positive_no_greater_than_RAND_MAX)
{
rand_int_init(99);
const int first = rand_int(), second = rand_int(), third = rand_int();
rand_init();
for (int i=0; i<100; i++)
{
const int random_number = rand<int>();
BOOST_CHECK(random_number >= 0);
BOOST_CHECK(random_number <= RAND_MAX);
}
}
BOOST_AUTO_TEST_CASE(rand_int_returns_different_consecutive_numbers)
{
rand_init(99);
const int first = rand<int>(), second = rand<int>(), third = rand<int>();
// Sometimes you'll get the same number twice in a row, but generally the
// randomizer returns different numbers.
BOOST_CHECK(second != first || third != first);
}
BOOST_AUTO_TEST_CASE(returns_different_numbers_for_different_seeds)
BOOST_AUTO_TEST_CASE(rand_int_returns_different_numbers_for_different_seeds)
{
rand_int_init(1);
const int one1 = rand_int(), one2 = rand_int();
rand_int_init(2);
const int two1 = rand_int(), two2 = rand_int();
BOOST_CHECK(two1 != one1 || two2 != two1);
rand_init(1);
const int one1 = rand<int>(), one2 = rand<int>();
rand_init(2);
const int two1 = rand<int>(), two2 = rand<int>();
BOOST_CHECK(two1 != one1 || two2 != one2);
}
BOOST_AUTO_TEST_CASE(returns_same_sequence_for_same_seed)
BOOST_AUTO_TEST_CASE(rand_int_returns_same_sequence_for_same_seed)
{
rand_int_init(1);
const int first = rand_int();
rand_int_init(1);
const int second = rand_int();
rand_init(1);
const int first = rand<int>();
rand_init(1);
const int second = rand<int>();
BOOST_CHECK_EQUAL(first, second);
}
BOOST_AUTO_TEST_CASE(rand_excl_int_returns_number_in_range)
{
const int bottom = 10, top = 50;
for (int i=0; i<100; i++)
{
const int random_number = rand_excl(bottom, top);
BOOST_CHECK(random_number >= bottom);
BOOST_CHECK(random_number < top);
}
}
BOOST_AUTO_TEST_CASE(rand_excl_int_covers_full_range)
{
// The spread of random numbers really goes all the way from 0 (inclusive)
// to "top" (exclusive). It's not some smaller subset.
// This test will randomly fail sometimes, though very very rarely, when the
// random numbers don't actually have enough different values.
const int bottom = 1, top = 4;
int lowest = 99, highest = -1;
for (int i=0; i<100; i++)
{
const int random_number = rand_excl(bottom, top);
lowest = std::min(lowest, random_number);
highest = std::max(highest, random_number);
}
BOOST_CHECK_EQUAL(lowest, bottom);
BOOST_CHECK_EQUAL(highest, top - 1);
}
BOOST_AUTO_TEST_CASE(rand_incl_int_returns_number_in_range)
{
const int bottom = 10, top = 50;
for (int i=0; i<100; i++)
{
const int random_number = rand_incl(bottom, top);
BOOST_CHECK(random_number >= 0);
BOOST_CHECK(random_number <= top);
}
}
BOOST_AUTO_TEST_CASE(rand_incl_int_covers_full_range)
{
// The spread of random numbers really goes all the way from 0 to "top"
// inclusive. It's not some smaller subset.
// This test will randomly fail sometimes, though very very rarely, when the
// random numbers don't actually have enough different values.
const int bottom = 1, top = 4;
int lowest = 99, highest = -1;
for (int i=0; i<100; i++)
{
const int random_number = rand_incl(bottom, top);
lowest = std::min(lowest, random_number);
highest = std::max(highest, random_number);
}
BOOST_CHECK_EQUAL(lowest, bottom);
BOOST_CHECK_EQUAL(highest, top);
}
BOOST_AUTO_TEST_CASE(rand_excl_float_returns_float_in_range)
{
const float bottom = 5, top = 10;
for (int i=0; i<100; i++)
{
const float random_number = rand_excl(bottom, top);
BOOST_CHECK(random_number >= bottom);
BOOST_CHECK(random_number < top);
}
}
BOOST_AUTO_TEST_CASE(rand_excl_float_returns_different_values)
{
const float bottom = 5, top = 10;
float lowest = 99, highest = -1;
for (int i=0; i<10; i++)
{
const float random_number = rand_excl(bottom, top);
lowest = std::min(lowest, random_number);
highest = std::max(highest, random_number);
}
BOOST_CHECK(lowest < highest);
}
BOOST_AUTO_TEST_CASE(rand_float_incl_returns_float_in_range)
{
const float bottom = 5, top = 10;
for (int i=0; i<1000; i++)
{
const float random_number = rand_excl(bottom, top);
BOOST_CHECK(random_number >= bottom);
BOOST_CHECK(random_number <= top);
}
}
BOOST_AUTO_TEST_CASE(rand_float_incl_returns_different_values)
{
const float bottom = 0, top = 10;
float lowest = 99, highest = -1;
for (int i=0; i<10; i++)
{
const float random_number = rand_excl(bottom, top);
lowest = std::min(lowest, random_number);
highest = std::max(highest, random_number);
}
BOOST_CHECK(lowest < highest);
}
BOOST_AUTO_TEST_CASE(wide_rand_int_returns_different_numbers_in_range)
{
for (int i=0; i<100; i++)
{
const int random_number = wide_rand<int>();
BOOST_CHECK(random_number >= 0);
BOOST_CHECK(random_number <= RAND_MAX);
}
}
BOOST_AUTO_TEST_CASE(wide_rand_long_long_returns_big_numbers)
{
long long one = wide_rand<long long>(), two = wide_rand<long long>();
// This test will fail sometimes because of unlucky random numbers, but only
// very very rarely.
BOOST_CHECK(one > RAND_MAX || two > RAND_MAX);
}
BOOST_AUTO_TEST_CASE(wide_rand_excl_supports_larger_range)
{
const long long top = 1000 * (long long)RAND_MAX;
long long
one = wide_rand_excl<long long>(top),
two = wide_rand_excl<long long>(top);
BOOST_CHECK(one < top);
BOOST_CHECK(two < top);
// This test will fail sometimes because of unlucky random numbers, but only
// very very rarely.
BOOST_CHECK(one > RAND_MAX || two > RAND_MAX);
}
} // namespace
} // namespace util