mirror of
https://github.com/moses-smt/mosesdecoder.git
synced 2024-12-25 21:03:22 +03:00
Add cross-platform randomizer module.
The code uses two mechanisms for generating random numbers: srand()/rand(), which is not thread-safe, and srandom()/random(), which is POSIX-specific. Here I add a util/random.cc module that centralizes these calls, and unifies some common usage patterns. If the implementation is not good enough, we can now change it in a single place. To keep things simple, this uses the portable srand()/rand() but protects them with a lock to avoid concurrency problems. The hard part was to keep the regression tests passing: they rely on fixed sequences of random numbers, so a small code change could break them very thoroughly. Util::rand(), for wide types like size_t, calls std::rand() not once but twice. This behaviour was generalized into utils::wide_rand() and friends.
This commit is contained in:
parent
4b47e1148c
commit
38d790cac0
@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
#include "moses/Word.h"
|
#include "moses/Word.h"
|
||||||
#include "moses/FF/FeatureFunction.h"
|
#include "moses/FF/FeatureFunction.h"
|
||||||
#include "Decoder.h"
|
#include "Decoder.h"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
typedef std::map<const Moses::FeatureFunction*, std::vector< float > > ProducerWeightMap;
|
typedef std::map<const Moses::FeatureFunction*, std::vector< float > > ProducerWeightMap;
|
||||||
typedef std::pair<const Moses::FeatureFunction*, std::vector< float > > ProducerWeightPair;
|
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 {
|
struct RandomIndex {
|
||||||
ptrdiff_t operator()(ptrdiff_t max) {
|
ptrdiff_t operator()(ptrdiff_t max) {
|
||||||
srand(time(0)); // Initialize random number generator with current time.
|
// TODO: Don't seed the randomizer here. If this function gets called
|
||||||
return static_cast<ptrdiff_t> (rand() % max);
|
// 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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
#include "RelativeEntropyCalc.h"
|
#include "RelativeEntropyCalc.h"
|
||||||
#include "LexicalReordering.h"
|
#include "LexicalReordering.h"
|
||||||
#include "LexicalReorderingState.h"
|
#include "LexicalReorderingState.h"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
#ifdef HAVE_PROTOBUF
|
#ifdef HAVE_PROTOBUF
|
||||||
#include "hypergraph.pb.h"
|
#include "hypergraph.pb.h"
|
||||||
@ -205,7 +206,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
|
|
||||||
//initialise random numbers
|
//initialise random numbers
|
||||||
srand(time(NULL));
|
rand_init();
|
||||||
|
|
||||||
// set up read/writing class
|
// set up read/writing class
|
||||||
IOWrapper* ioWrapper = GetIOWrapper(staticData);
|
IOWrapper* ioWrapper = GetIOWrapper(staticData);
|
||||||
|
@ -287,7 +287,7 @@ void Data::createShards(size_t shard_count, float shard_size, const string& scor
|
|||||||
} else {
|
} else {
|
||||||
//create shards by randomly sampling
|
//create shards by randomly sampling
|
||||||
for (size_t i = 0; i < floor(shard_size+0.5); ++i) {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +58,8 @@ void Point::Randomize()
|
|||||||
UTIL_THROW_IF(m_min.size() != Point::m_dim, util::Exception, "Error");
|
UTIL_THROW_IF(m_min.size() != Point::m_dim, util::Exception, "Error");
|
||||||
UTIL_THROW_IF(m_max.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++) {
|
for (unsigned int i = 0; i < size(); i++)
|
||||||
const float scale = (m_max[i] - m_min[i]) / float(RAND_MAX);
|
operator[](i) = util::rand_incl(m_min[i], m_max[i]);
|
||||||
operator[](i) = m_min[i] + util::rand_int() * scale;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double Point::operator*(const FeatureStats& F) const
|
double Point::operator*(const FeatureStats& F) const
|
||||||
|
@ -5,11 +5,8 @@
|
|||||||
|
|
||||||
- check that --pairwise-ranked is compatible with all optimization metrics
|
- check that --pairwise-ranked is compatible with all optimization metrics
|
||||||
|
|
||||||
- Replace the standard rand() currently used in MERT and PRO with better
|
- Use better random generators in util/random.cc, e.g. boost::mt19937.
|
||||||
random generators such as Boost's random generators (e.g., boost::mt19937).
|
- Support plugging of custom random generators.
|
||||||
- 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.
|
|
||||||
|
|
||||||
Pros:
|
Pros:
|
||||||
- In MERT, you might want to use the random restarting technique to avoid
|
- In MERT, you might want to use the random restarting technique to avoid
|
||||||
|
@ -95,7 +95,7 @@ void EvaluatorUtil::evaluate(const string& candFile, int bootstrap, bool nbest_i
|
|||||||
for (int i = 0; i < bootstrap; ++i) {
|
for (int i = 0; i < bootstrap; ++i) {
|
||||||
ScoreData scoredata(g_scorer);
|
ScoreData scoredata(g_scorer);
|
||||||
for (int j = 0; j < n; ++j) {
|
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);
|
scoredata.add(entries[randomIndex], j);
|
||||||
}
|
}
|
||||||
g_scorer->setScoreData(&scoredata);
|
g_scorer->setScoreData(&scoredata);
|
||||||
@ -285,10 +285,10 @@ void InitSeed(const ProgramOption *opt)
|
|||||||
{
|
{
|
||||||
if (opt->has_seed) {
|
if (opt->has_seed) {
|
||||||
cerr << "Seeding random numbers with " << opt->seed << endl;
|
cerr << "Seeding random numbers with " << opt->seed << endl;
|
||||||
util::rand_int_init(opt->seed);
|
util::rand_init(opt->seed);
|
||||||
} else {
|
} else {
|
||||||
cerr << "Seeding random numbers with system clock " << endl;
|
cerr << "Seeding random numbers with system clock " << endl;
|
||||||
util::rand_int_init();
|
util::rand_init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ de recherches du Canada
|
|||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
|
||||||
#include "util/exception.hh"
|
#include "util/exception.hh"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
#include "BleuScorer.h"
|
#include "BleuScorer.h"
|
||||||
#include "HopeFearDecoder.h"
|
#include "HopeFearDecoder.h"
|
||||||
@ -122,10 +123,10 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
if (vm.count("random-seed")) {
|
if (vm.count("random-seed")) {
|
||||||
cerr << "Initialising random seed to " << seed << endl;
|
cerr << "Initialising random seed to " << seed << endl;
|
||||||
srand(seed);
|
util::rand_init(seed);
|
||||||
} else {
|
} else {
|
||||||
cerr << "Initialising random seed from system clock" << endl;
|
cerr << "Initialising random seed from system clock" << endl;
|
||||||
srand(time(NULL));
|
util::rand_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize weights
|
// Initialize weights
|
||||||
|
@ -290,10 +290,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (option.has_seed) {
|
if (option.has_seed) {
|
||||||
cerr << "Seeding random numbers with " << option.seed << endl;
|
cerr << "Seeding random numbers with " << option.seed << endl;
|
||||||
util::rand_int_init(option.seed);
|
util::rand_init(option.seed);
|
||||||
} else {
|
} else {
|
||||||
cerr << "Seeding random numbers with system clock " << endl;
|
cerr << "Seeding random numbers with system clock " << endl;
|
||||||
util::rand_int_init();
|
util::rand_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option.sparse_weights_file.size()) ++option.pdim;
|
if (option.sparse_weights_file.size()) ++option.pdim;
|
||||||
|
@ -43,6 +43,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
#include "ScoreDataIterator.h"
|
#include "ScoreDataIterator.h"
|
||||||
#include "BleuScorer.h"
|
#include "BleuScorer.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace MosesTuning;
|
using namespace MosesTuning;
|
||||||
@ -141,10 +142,10 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
if (vm.count("random-seed")) {
|
if (vm.count("random-seed")) {
|
||||||
cerr << "Initialising random seed to " << seed << endl;
|
cerr << "Initialising random seed to " << seed << endl;
|
||||||
srand(seed);
|
util::rand_init(seed);
|
||||||
} else {
|
} else {
|
||||||
cerr << "Initialising random seed from system clock" << endl;
|
cerr << "Initialising random seed from system clock" << endl;
|
||||||
srand(time(NULL));
|
util::rand_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scoreFiles.size() == 0 || featureFiles.size() == 0) {
|
if (scoreFiles.size() == 0 || featureFiles.size() == 0) {
|
||||||
@ -211,11 +212,11 @@ int main(int argc, char** argv)
|
|||||||
vector<float> scores;
|
vector<float> scores;
|
||||||
size_t n_translations = hypotheses.size();
|
size_t n_translations = hypotheses.size();
|
||||||
for(size_t i=0; i<n_candidates; i++) {
|
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];
|
pair<size_t,size_t> translation1 = hypotheses[rand1];
|
||||||
float bleu1 = smoothedSentenceBleu(scoreDataIters[translation1.first]->operator[](translation1.second), bleuSmoothing, smoothBP);
|
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];
|
pair<size_t,size_t> translation2 = hypotheses[rand2];
|
||||||
float bleu2 = smoothedSentenceBleu(scoreDataIters[translation2.first]->operator[](translation2.second), bleuSmoothing, smoothBP);
|
float bleu2 = smoothedSentenceBleu(scoreDataIters[translation2.first]->operator[](translation2.second), bleuSmoothing, smoothBP);
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
#include "moses/FF/StatefulFeatureFunction.h"
|
#include "moses/FF/StatefulFeatureFunction.h"
|
||||||
#include "moses/FF/StatelessFeatureFunction.h"
|
#include "moses/FF/StatelessFeatureFunction.h"
|
||||||
#include "moses/TrainingTask.h"
|
#include "moses/TrainingTask.h"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
#ifdef HAVE_PROTOBUF
|
#ifdef HAVE_PROTOBUF
|
||||||
#include "hypergraph.pb.h"
|
#include "hypergraph.pb.h"
|
||||||
@ -117,7 +118,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
|
|
||||||
//initialise random numbers
|
//initialise random numbers
|
||||||
srand(time(NULL));
|
util::rand_init();
|
||||||
|
|
||||||
// set up read/writing class
|
// set up read/writing class
|
||||||
IFVERBOSE(1) {
|
IFVERBOSE(1) {
|
||||||
|
@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "util/random.hh"
|
||||||
#include "util/usage.hh"
|
#include "util/usage.hh"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -91,7 +92,7 @@ SimpleTranslationInterface::SimpleTranslationInterface(const string &mosesIni):
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
srand(time(NULL));
|
util::rand_init();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ batch_run()
|
|||||||
const StaticData& staticData = StaticData::Instance();
|
const StaticData& staticData = StaticData::Instance();
|
||||||
|
|
||||||
//initialise random numbers
|
//initialise random numbers
|
||||||
srand(time(NULL));
|
util::rand_init();
|
||||||
|
|
||||||
IFVERBOSE(1) PrintUserTime("Created input-output object");
|
IFVERBOSE(1) PrintUserTime("Created input-output object");
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "util/exception.hh"
|
#include "util/exception.hh"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -418,7 +419,7 @@ void Manager::CalcLatticeSamples(size_t count, TrellisPathList &ret) const
|
|||||||
//cerr << endl;
|
//cerr << endl;
|
||||||
|
|
||||||
//draw the sample
|
//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;
|
size_t position = 1;
|
||||||
float sum = candidateScores[0];
|
float sum = candidateScores[0];
|
||||||
for (; position < candidateScores.size() && sum < frandom; ++position) {
|
for (; position < candidateScores.size() && sum < frandom; ++position) {
|
||||||
|
@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||||||
#include "InputFileStream.h"
|
#include "InputFileStream.h"
|
||||||
#include "StaticData.h"
|
#include "StaticData.h"
|
||||||
#include "util/exception.hh"
|
#include "util/exception.hh"
|
||||||
|
#include "util/random.hh"
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
|
|
||||||
@ -1392,7 +1393,7 @@ struct Credit {
|
|||||||
this->contact = contact ;
|
this->contact = contact ;
|
||||||
this->currentPursuits = currentPursuits ;
|
this->currentPursuits = currentPursuits ;
|
||||||
this->areaResponsibility = areaResponsibility;
|
this->areaResponsibility = areaResponsibility;
|
||||||
this->sortId = rand() % 1000;
|
this->sortId = util::rand_excl(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const Credit &other) const {
|
bool operator<(const Credit &other) const {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "FileHandler.h"
|
#include "FileHandler.h"
|
||||||
#include "util/exception.hh"
|
#include "util/exception.hh"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
using namespace Moses;
|
using namespace Moses;
|
||||||
typedef uint64_t P; // largest input range is 2^64
|
typedef uint64_t P; // largest input range is 2^64
|
||||||
@ -162,7 +163,7 @@ void Hash_shiftAddXOR<T>::initSeeds()
|
|||||||
{
|
{
|
||||||
v_ = new T[this->H_];
|
v_ = new T[this->H_];
|
||||||
for(count_t i=0; i < this->H_; i++)
|
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>
|
template <typename T>
|
||||||
T Hash_shiftAddXOR<T>::hash(const char* s, count_t h)
|
T Hash_shiftAddXOR<T>::hash(const char* s, count_t h)
|
||||||
@ -187,9 +188,8 @@ void UnivHash_tableXOR<T>::initSeeds()
|
|||||||
// fill with random values
|
// fill with random values
|
||||||
for(count_t j=0; j < this->H_; j++) {
|
for(count_t j=0; j < this->H_; j++) {
|
||||||
table_[j] = new T[tblLen_];
|
table_[j] = new T[tblLen_];
|
||||||
for(count_t i=0; i < tblLen_; i++) {
|
for(count_t i=0; i < tblLen_; i++)
|
||||||
table_[j][i] = Utils::rand<T>(this->m_-1);
|
table_[j][i] = util::wide_rand_excl(this->m_-1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -218,7 +218,7 @@ void UnivHash_noPrimes<T>::initSeeds()
|
|||||||
{
|
{
|
||||||
a_ = new P[this->H_];
|
a_ = new P[this->H_];
|
||||||
for(T i=0; i < this->H_; i++) {
|
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
|
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];
|
a_[i] = new T[MAX_NGRAM_ORDER];
|
||||||
b_[i] = new T[MAX_NGRAM_ORDER];
|
b_[i] = new T[MAX_NGRAM_ORDER];
|
||||||
for(count_t j=0; j < MAX_NGRAM_ORDER; j++) {
|
for(count_t j=0; j < MAX_NGRAM_ORDER; j++) {
|
||||||
a_[i][j] = 1 + Utils::rand<T>();
|
a_[i][j] = 1 + util::wide_rand<T>();
|
||||||
b_[i][j] = Utils::rand<T>();
|
b_[i][j] = util::wide_rand<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,22 +62,6 @@ public:
|
|||||||
str[i] = tolower(str[i]);
|
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
|
#endif
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "DynSuffixArray.h"
|
#include "DynSuffixArray.h"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
@ -315,33 +317,31 @@ int DynSuffixArray::Compare(int pos1, int pos2, int max)
|
|||||||
return 0;
|
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)
|
void DynSuffixArray::Qsort(int* array, int begin, int end)
|
||||||
{
|
{
|
||||||
if(end > begin) {
|
if(end > begin) {
|
||||||
int index;
|
int index = util::rand_incl(begin, end);
|
||||||
{
|
{
|
||||||
index = begin + (rand() % (end - begin + 1));
|
const int pivot = array[index];
|
||||||
int pivot = array[index];
|
swap_ints(array, index, end);
|
||||||
{
|
|
||||||
int tmp = array[index];
|
|
||||||
array[index] = array[end];
|
|
||||||
array[end] = tmp;
|
|
||||||
}
|
|
||||||
for(int i=index=begin; i < end; ++i) {
|
for(int i=index=begin; i < end; ++i) {
|
||||||
if (Compare(array[i], pivot, 20) <= 0) {
|
if (Compare(array[i], pivot, 20) <= 0) {
|
||||||
{
|
swap_ints(array, index, i);
|
||||||
int tmp = array[index];
|
|
||||||
array[index] = array[i];
|
|
||||||
array[i] = tmp;
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
swap_ints(array, index, end);
|
||||||
{
|
|
||||||
int tmp = array[index];
|
|
||||||
array[index] = array[end];
|
|
||||||
array[end] = tmp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Qsort(array, begin, index - 1);
|
Qsort(array, begin, index - 1);
|
||||||
Qsort(array, index + 1, end);
|
Qsort(array, index + 1, end);
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "moses/TranslationModel/fuzzy-match/SentenceAlignment.h"
|
#include "moses/TranslationModel/fuzzy-match/SentenceAlignment.h"
|
||||||
#include "util/file.hh"
|
#include "util/file.hh"
|
||||||
#include "util/exception.hh"
|
#include "util/exception.hh"
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -62,8 +63,8 @@ char *mkdtemp(char *tempbuf)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srand((unsigned)time(0));
|
util::rand_init();
|
||||||
rand_value = (int)((rand() / ((double)RAND_MAX+1.0)) * 1e6);
|
rand_value = rand_excl(1e6);
|
||||||
tempbase = strrchr(tempbuf, '/');
|
tempbase = strrchr(tempbuf, '/');
|
||||||
tempbase = tempbase ? tempbase+1 : tempbuf;
|
tempbase = tempbase ? tempbase+1 : tempbuf;
|
||||||
strcpy(tempbasebuf, tempbase);
|
strcpy(tempbasebuf, tempbase);
|
||||||
|
@ -2,19 +2,16 @@
|
|||||||
#define __sampling_h
|
#define __sampling_h
|
||||||
#include <boost/dynamic_bitset.hpp>
|
#include <boost/dynamic_bitset.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "util/random.hh"
|
||||||
|
|
||||||
// Utility functions for proper sub-sampling.
|
// Utility functions for proper sub-sampling.
|
||||||
// (c) 2007-2012 Ulrich Germann
|
// (c) 2007-2012 Ulrich Germann
|
||||||
|
|
||||||
|
|
||||||
namespace Moses
|
namespace Moses
|
||||||
{
|
{
|
||||||
using namespace std;
|
using namespace std;
|
||||||
inline
|
|
||||||
size_t
|
|
||||||
randInt(size_t N)
|
|
||||||
{
|
|
||||||
return N*(rand()/(RAND_MAX+1.));
|
|
||||||
}
|
|
||||||
|
|
||||||
// select a random sample of size /s/ without restitution from the range of
|
// select a random sample of size /s/ without restitution from the range of
|
||||||
// integers [0,N);
|
// integers [0,N);
|
||||||
@ -35,15 +32,15 @@ randomSample(vector<idx_t>& v, size_t s, size_t N)
|
|||||||
if (s*10<N) {
|
if (s*10<N) {
|
||||||
boost::dynamic_bitset<uint64_t> check(N,0);
|
boost::dynamic_bitset<uint64_t> check(N,0);
|
||||||
for (size_t i = 0; i < v.size(); i++) {
|
for (size_t i = 0; i < v.size(); i++) {
|
||||||
size_t x = randInt(N);
|
size_t x = util::rand_excl(N);
|
||||||
while (check[x]) x = randInt(N);
|
while (check[x]) x = util::rand_excl(N);
|
||||||
check[x]=true;
|
check[x]=true;
|
||||||
v[i] = x;
|
v[i] = x;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
size_t m=0;
|
size_t m=0;
|
||||||
for (size_t t = 0; m <= s && t < N; t++)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@
|
|||||||
// {
|
// {
|
||||||
// boost::lock_guard<boost::mutex> lock(stats->lock);
|
// boost::lock_guard<boost::mutex> lock(stats->lock);
|
||||||
// if (stats->raw_cnt == ctr) ++stats->raw_cnt;
|
// 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 << " "
|
// // cout << stats->raw_cnt << " " << ctr-1 << " "
|
||||||
// // << rnum << " " << max_samples - stats->good << endl;
|
// // << rnum << " " << max_samples - stats->good << endl;
|
||||||
// if (rnum < max_samples - stats->good)
|
// if (rnum < max_samples - stats->good)
|
||||||
|
@ -69,7 +69,7 @@ namespace ugdiss
|
|||||||
// while (chosen < samplesize && next < stop)
|
// while (chosen < samplesize && next < stop)
|
||||||
// {
|
// {
|
||||||
// root->readEntry(next,*this);
|
// root->readEntry(next,*this);
|
||||||
// if (randInt(N - sampled++) < samplesize - chosen)
|
// if (util::rand_excl(N - sampled++) < samplesize - chosen)
|
||||||
// {
|
// {
|
||||||
// ++chosen;
|
// ++chosen;
|
||||||
// return true;
|
// return true;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "util/exception.hh"
|
#include "util/exception.hh"
|
||||||
#include "moses/Util.h"
|
#include "moses/Util.h"
|
||||||
|
#include "util/random.hh"
|
||||||
//#include <cassert>
|
//#include <cassert>
|
||||||
|
|
||||||
// #include "ug_bv_iter.h"
|
// #include "ug_bv_iter.h"
|
||||||
@ -894,13 +895,6 @@ namespace ugdiss
|
|||||||
return bv;
|
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
|
/// randomly select up to N occurrences of the sequence
|
||||||
template<typename Token>
|
template<typename Token>
|
||||||
sptr<vector<typename ttrack::Position> >
|
sptr<vector<typename ttrack::Position> >
|
||||||
@ -922,8 +916,8 @@ namespace ugdiss
|
|||||||
root->readEntry(I.next,I);
|
root->readEntry(I.next,I);
|
||||||
|
|
||||||
// t: expected number of remaining samples
|
// t: expected number of remaining samples
|
||||||
double t = (stop - I.pos)/root->aveIndexEntrySize();
|
const double t = (stop - I.pos)/root->aveIndexEntrySize();
|
||||||
double r = t*rand()/(RAND_MAX+1.);
|
const double r = util::rand_excl(t);
|
||||||
if (r < N-m)
|
if (r < N-m)
|
||||||
{
|
{
|
||||||
ret->at(m).offset = I.offset;
|
ret->at(m).offset = I.offset;
|
||||||
|
@ -19,21 +19,25 @@ namespace
|
|||||||
boost::mutex rand_lock;
|
boost::mutex rand_lock;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void rand_int_init(unsigned int seed)
|
void rand_init(unsigned int seed)
|
||||||
{
|
{
|
||||||
boost::lock_guard<boost::mutex> lock(rand_lock);
|
boost::lock_guard<boost::mutex> lock(rand_lock);
|
||||||
srand(seed);
|
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()
|
int rand_int()
|
||||||
{
|
{
|
||||||
boost::lock_guard<boost::mutex> lock(rand_lock);
|
boost::lock_guard<boost::mutex> lock(rand_lock);
|
||||||
return rand();
|
return std::rand();
|
||||||
}
|
}
|
||||||
|
} // namespace internal
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
207
util/random.hh
207
util/random.hh
@ -1,32 +1,229 @@
|
|||||||
#ifndef UTIL_RANDOM_H
|
#ifndef UTIL_RANDOM_H
|
||||||
#define UTIL_RANDOM_H
|
#define UTIL_RANDOM_H
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
namespace util
|
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.
|
/** Initialize randomizer with a fixed seed.
|
||||||
*
|
*
|
||||||
* After this, unless the randomizer gets seeded again, consecutive calls to
|
* After this, unless the randomizer gets seeded again, consecutive calls to
|
||||||
* rand_int() will return a sequence of pseudo-random numbers determined by
|
* the random functions will return a sequence of pseudo-random numbers
|
||||||
* the seed. Every time the randomizer is seeded with this same seed, it will
|
* determined by the seed. Every time the randomizer is seeded with this same
|
||||||
* again start returning the same sequence of numbers.
|
* 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.
|
/** Initialize randomizer based on current time.
|
||||||
*
|
*
|
||||||
* Call this to make the randomizer return hard-to-predict numbers. It won't
|
* 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
|
* produce high-grade randomness, but enough to make the program act
|
||||||
* differently on different runs.
|
* 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.
|
/** Return a pseudorandom number between 0 and RAND_MAX inclusive.
|
||||||
*
|
*
|
||||||
* Initialize (seed) the randomizer before starting to call this.
|
* 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();
|
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
|
} // namespace util
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "util/random.hh"
|
#include "util/random.hh"
|
||||||
|
|
||||||
#define BOOST_TEST_MODULE RandomTest
|
#define BOOST_TEST_MODULE RandomTest
|
||||||
@ -8,32 +10,182 @@ namespace util
|
|||||||
namespace
|
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);
|
rand_init();
|
||||||
const int first = rand_int(), second = rand_int(), third = rand_int();
|
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
|
// Sometimes you'll get the same number twice in a row, but generally the
|
||||||
// randomizer returns different numbers.
|
// randomizer returns different numbers.
|
||||||
BOOST_CHECK(second != first || third != first);
|
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);
|
rand_init(1);
|
||||||
const int one1 = rand_int(), one2 = rand_int();
|
const int one1 = rand<int>(), one2 = rand<int>();
|
||||||
rand_int_init(2);
|
rand_init(2);
|
||||||
const int two1 = rand_int(), two2 = rand_int();
|
const int two1 = rand<int>(), two2 = rand<int>();
|
||||||
BOOST_CHECK(two1 != one1 || two2 != two1);
|
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);
|
rand_init(1);
|
||||||
const int first = rand_int();
|
const int first = rand<int>();
|
||||||
rand_int_init(1);
|
rand_init(1);
|
||||||
const int second = rand_int();
|
const int second = rand<int>();
|
||||||
BOOST_CHECK_EQUAL(first, second);
|
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
|
||||||
} // namespace util
|
} // namespace util
|
||||||
|
Loading…
Reference in New Issue
Block a user