1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
// ----------------------------------------------------------------------
//
// testBug58950 -- test problem with RanecuEngine on 64bit machines
//
// R. Weller 11/11/09 initial test from Vanderbilt
// L. Garren 12/1/09 rewritten for test suite
//
// ----------------------------------------------------------------------
#include <iostream>
#include <stdexcept>
#include <cmath>
#include <stdlib.h>
#include "CLHEP/Random/RanecuEngine.h"
#include "CLHEP/Random/Random.h"
#include "pretend.h"
// Absolutely Safe Equals Without Registers Screwing Us Up
bool equals01(const std::vector<double> &ab) {
return ab[1]==ab[0];
}
bool equals(double a, double b) {
std::vector<double> ab(2);
ab[0]=a; ab[1]=b;
return (equals01(ab));
}
bool printCheck( int & i, double & r, std::ofstream & os )
{
os << i << " " << r << std::endl;
if (r < 0 || r > 1.0 ) {
std::cout << "Error: bad random number " << r << std::endl;
return false;
}
return true;
}
int main() {
std::ofstream output("testBug58950.cout");
output << std::endl << "short " << sizeof(short) << std::endl;
output << "int " << sizeof(int) << std::endl;
output << "unsigned int " << sizeof(unsigned int) << std::endl;
output << "long " << sizeof(long) << std::endl;
output << "float " << sizeof(float) << std::endl;
output << "double " << sizeof(double) << std::endl;
output << "long double " << sizeof(long double) << std::endl << std::endl;
CLHEP::RanecuEngine *eng = new CLHEP::RanecuEngine;
CLHEP::HepRandom::setTheEngine(eng);
CLHEP::HepRandom *g;
g=CLHEP::HepRandom::getTheGenerator();
long rvals[2];
try {
std::ifstream in("/dev/urandom", std::ios::in | std::ios::binary);
if(in.is_open()) {
in.read((char *)(&rvals), 2*sizeof(long));
in.close();
if(in.fail()) {
throw std::runtime_error("File read error");
}
} else throw std::runtime_error("File open error");
} catch(std::runtime_error e) {
std::ostringstream dStr;
dStr << "Error: " << e.what()
<< " processing seed from file \"" << "/dev/urandom" << "\".";
throw std::runtime_error(dStr.str().c_str());
}
int nNumbers = 20;
int badcount = 0;
long seeds[3];
const long *pseeds;
//***********************************************************************
// Seeds are expected to be positive. Therefore, if either seed is
// negative then prior to 2.0.4.5 the generator set initial conditions
// and generated the same sequence of numbers no matter what the seeds were.
seeds[0]=rvals[0];
seeds[1]=rvals[1];
seeds[2]=0;
if( rvals[0] > 0 ) seeds[0] = -rvals[0];
double negseq[20] = { 0.154707, 0.587114, 0.702059, 0.566, 0.988325,
0.525921, 0.191554, 0.269338, 0.234277, 0.358997,
0.549936, 0.296877, 0.162243, 0.227732, 0.528862,
0.631571, 0.176462, 0.247858, 0.170025, 0.284483 };
double eps = 1.0E-6;
output << std::endl << "********************" << std::endl;
output << "This is the case that may or may not fail." << std::endl;
output << "However, if it has values in (0,1), they are a " << std::endl
<< "deterministic sequence beginning with 0.154707." << std::endl;
output << "seeds[0] = " << seeds[0] << "\n"
<< "seeds[1] = " << seeds[1] << std::endl << std::endl;
g->setTheSeeds(seeds);
int rseq = 0;
for (int i=0; i < nNumbers; ++i) {
double r = g->flat();
if( ! printCheck(i,r,output) ) ++badcount;
// before the change, the random number sequence was reliably the same
if( std::fabs(r-negseq[i]) < eps ) {
std::cout << " reproducing sequence " << i << " "
<< r << " " << negseq[i] << std::endl;
++rseq;
}
}
if( rseq == 20 ) ++badcount;
pseeds=g->getTheSeeds();
output << "Final seeds[0] = " << pseeds[0] << "\n"
<< "Final seeds[1] = " << pseeds[1] << std::endl << std::endl;
//***********************************************************************
// Prior to the 2.0.4.5 bug fix, 64bit seeds resulted in incorrect randoms
seeds[0]=labs(rvals[0]);
seeds[1]=labs(rvals[1]);
seeds[2]=0;
output << std::endl << "********************" << std::endl;
output << "This is the case that always fails." << std::endl;
output << "seeds[0] = " << seeds[0] << "\n"
<< "seeds[1] = " << seeds[1] << std::endl << std::endl;
g->setTheSeeds(seeds);
for (int i=0; i < nNumbers; ++i) {
double r = g->flat();
if( ! printCheck(i,r,output) ) ++badcount;
}
pseeds=g->getTheSeeds();
output << "Final seeds[0] = " << pseeds[0] << "\n"
<< "Final seeds[1] = " << pseeds[1] << std::endl << std::endl;
//***********************************************************************
// recover and reuse seeds
seeds[0]=labs(rvals[0]);
seeds[1]=labs(rvals[1]);
seeds[2]=0;
output << std::endl << "********************" << std::endl;
output << "Check rolling back a random number seed." << std::endl;
output << "seeds[0] = " << seeds[0] << "\n"
<< "seeds[1] = " << seeds[1] << std::endl << std::endl;
std::vector<double> v;
g->setTheSeeds(seeds);
for (int i=0; i < nNumbers; ++i) {
double r = g->flat();
if( ! printCheck(i,r,output) ) ++badcount;
}
pseeds=g->getTheSeeds();
seeds[0] = pseeds[0];
seeds[1] = pseeds[1];
output << " pseeds[0] = " << pseeds[0] << "\n"
<< "pseeds[1] = " << pseeds[1] << std::endl;
for (int i=0; i < nNumbers; ++i) {
double r = g->flat();
v.push_back(r);
}
g->setTheSeeds(seeds);
for (int i=0; i < nNumbers; ++i) {
double r = g->flat();
if(! equals(v[i],r) ) {
++badcount;
std::cerr << " rollback fails: i, v[i], r "
<< i << " " << v[i] << " " << r << std::endl;
}
}
output << std::endl;
//***********************************************************************
// 4-byte positive integers generate valid sequences, which remain within bounds.
seeds[0]= labs(static_cast<int>(rvals[0]));
seeds[1]= labs(static_cast<int>(rvals[1]));
seeds[2]=0;
output << std::endl << "********************" << std::endl;
output << "This is the case that works." << std::endl;
output << std::endl << "seeds[0] = " << seeds[0] << "\n"
<< "seeds[1] = " << seeds[1] << "\n"
<< "seeds[2] = " << seeds[2] << std::endl << std::endl;
g->setTheSeeds(seeds);
for (int i=0; i < nNumbers; ++i) {
double r = g->flat();
if( ! printCheck(i,r,output) ) ++badcount;
}
pseeds=g->getTheSeeds();
output << "Final seeds[0] = " << pseeds[0] << "\n"
<< "Final seeds[1] = " << pseeds[1] << std::endl << std::endl;
//***********************************************************************
// Before the fix, a bad 64bit sequence would eventually rectify itself.
// This starts with seeds that would have failed before the 64bit corrections
// were applied and loops until both seeds are positive 32-bit integers.
// This looping should no longer occur.
seeds[0]=labs(rvals[0]);
seeds[1]=labs(rvals[1]);
seeds[2]=0;
output << std::endl << "********************" << std::endl;
output << "This case loops until valid short seeds occur." << std::endl;
output << "seeds[0] = " << seeds[0] << "\n"
<< "seeds[1] = " << seeds[1] << std::endl << std::endl;
g->setTheSeeds(seeds);
// Loop as long as the values are bad.
double r;
unsigned int low = ~0;
unsigned long mask = (~0) << 31;
unsigned long skipcount = 0;
output << "low = " << low << " mask = " << mask << std::endl;
do {
r = g->flat();
pretend_to_use( r );
pseeds = g->getTheSeeds();
++skipcount;
} while((pseeds[0]&mask) || (pseeds[1]&mask));
if ( skipcount > 1 ) ++badcount;
output << std::endl << "Loop terminates on two short seeds." << std::endl;
output << "Skipcount = " << skipcount << std::endl;
output << "pseeds[0]&mask = " << (pseeds[0]&mask) << std::endl;
output << "pseeds[1]&mask = " << (pseeds[1]&mask) << std::endl;
output << "Final seeds[0] = " << pseeds[0] << "\n"
<< "Final seeds[1] = " << pseeds[1] << std::endl << std::endl;
output << "This should be a valid sequence." << std::endl;
for (int i=0; i < nNumbers; ++i) {
double r1 = g->flat();
if( ! printCheck(i,r1,output) ) ++badcount;
}
pseeds=g->getTheSeeds();
output << "seeds[0] = " << pseeds[0] << "\n"
<< "seeds[1] = " << pseeds[1] << std::endl << std::endl;
if( badcount > 0 ) std::cout << "Error count is " << badcount << std::endl;
return badcount;
}
|