717 lines
20 KiB
C++
717 lines
20 KiB
C++
// -*- C++ -*-
|
|
//
|
|
// -----------------------------------------------------------------------
|
|
// HEP Random
|
|
// --- Ranlux64Engine ---
|
|
// class implementation file
|
|
// -----------------------------------------------------------------------
|
|
// A double-precision implementation of the RanluxEngine generator as
|
|
// decsribed by the notes of the original ranlux author (Martin Luscher)
|
|
//
|
|
// See the note by Martin Luscher, December 1997, entitiled
|
|
// Double-precision implementation of the random number generator ranlux
|
|
//
|
|
// =======================================================================
|
|
// Ken Smith - Initial draft: 14th Jul 1998
|
|
// - Removed pow() from flat method 14th Jul 1998
|
|
// - Added conversion operators: 6th Aug 1998
|
|
//
|
|
// Mark Fischler The following were modified mostly to make the routine
|
|
// exactly match the Luscher algorithm in generating 48-bit
|
|
// randoms:
|
|
// 9/9/98 - Substantial changes in what used to be flat() to match
|
|
// algorithm in Luscher's ranlxd.c
|
|
// - Added update() method for 12 numbers, making flat() trivial
|
|
// - Added advance() method to hold the unrolled loop for update
|
|
// - Distinction between three forms of seeding such that it
|
|
// is impossible to get same sequence from different forms -
|
|
// done by discarding some fraction of one macro cycle which
|
|
// is different for the three cases
|
|
// - Change the misnomer "seed_table" to the more accurate
|
|
// "randoms"
|
|
// - Removed the no longer needed count12, i_lag, j_lag, etc.
|
|
// - Corrected seed procedure which had been filling bits past
|
|
// 2^-48. This actually was very bad, invalidating the
|
|
// number theory behind the proof that ranlxd is good.
|
|
// - Addition of 2**(-49) to generated number to prevent zero
|
|
// from being returned; this does not affect the sequence
|
|
// itself.
|
|
// - Corrected ecu seeding, which had been supplying only
|
|
// numbers less than 1/2. This is probably moot.
|
|
// 9/15/98 - Modified use of the various exponents of 2
|
|
// to avoid per-instance space overhead. Note that these
|
|
// are initialized in setSeed, which EVERY constructor
|
|
// must invoke.
|
|
// J. Marraffino - Remove dependence on hepString class 13 May 1999
|
|
// M. Fischler - In restore, checkFile for file not found 03 Dec 2004
|
|
// M. Fischler - put get Methods for distrib instance save/restore 12/8/04
|
|
// M. Fischler - split get() into tag validation and
|
|
// getState() for anonymous restores 12/27/04
|
|
// M. Fischler - put/get for vectors of ulongs 3/14/05
|
|
// M. Fischler - State-saving using only ints, for portability 4/12/05
|
|
//
|
|
// =======================================================================
|
|
|
|
#include "CLHEP/Random/Random.h"
|
|
#include "CLHEP/Random/Ranlux64Engine.h"
|
|
#include "CLHEP/Random/engineIDulong.h"
|
|
#include "CLHEP/Random/DoubConv.h"
|
|
#include "CLHEP/Utility/atomic_int.h"
|
|
|
|
#include <atomic>
|
|
#include <cstdlib> // for std::abs(int)
|
|
#include <iostream>
|
|
#include <limits> // for numeric_limits
|
|
#include <string.h> // for strcmp
|
|
#include <vector>
|
|
|
|
namespace CLHEP {
|
|
|
|
namespace {
|
|
// Number of instances with automatic seed selection
|
|
CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
|
|
|
|
// Maximum index into the seed table
|
|
const int maxIndex = 215;
|
|
}
|
|
|
|
static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
|
|
|
|
|
|
#ifndef WIN32
|
|
namespace detail {
|
|
|
|
template< std::size_t n,
|
|
bool = n < std::size_t(std::numeric_limits<unsigned long>::digits) >
|
|
struct do_right_shift;
|
|
template< std::size_t n >
|
|
struct do_right_shift<n,true>
|
|
{
|
|
unsigned long operator()(unsigned long value) { return value >> n; }
|
|
};
|
|
template< std::size_t n >
|
|
struct do_right_shift<n,false>
|
|
{
|
|
unsigned long operator()(unsigned long) { return 0ul; }
|
|
};
|
|
|
|
template< std::size_t nbits >
|
|
unsigned long rshift( unsigned long value )
|
|
{ return do_right_shift<nbits>()(value); }
|
|
|
|
} // namespace detail
|
|
#endif
|
|
|
|
std::string Ranlux64Engine::name() const {return "Ranlux64Engine";}
|
|
|
|
Ranlux64Engine::Ranlux64Engine()
|
|
: HepRandomEngine()
|
|
{
|
|
luxury = 1;
|
|
int numEngines = numberOfEngines++;
|
|
int cycle = std::abs(int(numEngines/maxIndex));
|
|
int curIndex = std::abs(int(numEngines%maxIndex));
|
|
|
|
long mask = ((cycle & 0x007fffff) << 8);
|
|
long seedlist[2];
|
|
HepRandom::getTheTableSeeds( seedlist, curIndex );
|
|
seedlist[0] ^= mask;
|
|
seedlist[1] = 0;
|
|
|
|
setSeeds(seedlist, luxury);
|
|
advance ( 8 ); // Discard some iterations and ensure that
|
|
// this sequence won't match one where seeds
|
|
// were provided.
|
|
}
|
|
|
|
Ranlux64Engine::Ranlux64Engine(long seed, int lux)
|
|
: HepRandomEngine()
|
|
{
|
|
luxury = lux;
|
|
long seedlist[2]={seed,0};
|
|
setSeeds(seedlist, lux);
|
|
advance ( 2*lux + 1 ); // Discard some iterations to use a different
|
|
// point in the sequence.
|
|
}
|
|
|
|
Ranlux64Engine::Ranlux64Engine(int rowIndex, int, int lux)
|
|
: HepRandomEngine()
|
|
{
|
|
luxury = lux;
|
|
int cycle = std::abs(int(rowIndex/maxIndex));
|
|
int row = std::abs(int(rowIndex%maxIndex));
|
|
long mask = (( cycle & 0x000007ff ) << 20 );
|
|
long seedlist[2];
|
|
HepRandom::getTheTableSeeds( seedlist, row );
|
|
seedlist[0] ^= mask;
|
|
seedlist[1]= 0;
|
|
setSeeds(seedlist, lux);
|
|
}
|
|
|
|
Ranlux64Engine::Ranlux64Engine( std::istream& is )
|
|
: HepRandomEngine()
|
|
{
|
|
is >> *this;
|
|
}
|
|
|
|
Ranlux64Engine::~Ranlux64Engine() {}
|
|
|
|
double Ranlux64Engine::flat() {
|
|
// Luscher improves the speed by computing several numbers in a shot,
|
|
// in a manner similar to that of the Tausworth in DualRand or the Hurd
|
|
// engines. Thus, the real work is done in update(). Here we merely ensure
|
|
// that zero, which the algorithm can produce, is never returned by flat().
|
|
|
|
if (index <= 0) update();
|
|
return randoms[--index] + twoToMinus_49();
|
|
}
|
|
|
|
void Ranlux64Engine::update() {
|
|
// Update the stash of twelve random numbers.
|
|
// When this routione is entered, index is always 0. The randoms
|
|
// contains the last 12 numbers in the sequents: s[0] is x[a+11],
|
|
// s[1] is x[a+10] ... and s[11] is x[a] for some a. Carry contains
|
|
// the last carry value (c[a+11]).
|
|
//
|
|
// The recursion relation (3) in Luscher's note says
|
|
// delta[n] = x[n-s] = x[n-r] -c[n-1] or for n=a+12,
|
|
// delta[a+12] = x[a+7] - x[a] -c[a+11] where we use r=12, s=5 per eqn. (7)
|
|
// This reduces to
|
|
// s[11] = s[4] - s[11] - carry.
|
|
// The next number similarly will be given by s[10] = s[3] - s[10] - carry,
|
|
// and so forth until s[0] is filled.
|
|
//
|
|
// However, we need to skip 397, 202 or 109 numbers - these are not divisible
|
|
// by 12 - to "fare well in the spectral test".
|
|
|
|
advance(pDozens);
|
|
|
|
// Since we wish at the end to have the 12 last numbers in the order of
|
|
// s[11] first, till s[0] last, we will have to do 1, 10, or 1 iterations
|
|
// and then re-arrange to place to get the oldest one in s[11].
|
|
// Generically, this will imply re-arranging the s array at the end,
|
|
// but we can treat the special case of endIters = 1 separately for superior
|
|
// efficiency in the cases of levels 0 and 2.
|
|
|
|
double y1;
|
|
|
|
if ( endIters == 1 ) { // Luxury levels 0 and 2 will go here
|
|
y1 = randoms[ 4] - randoms[11] - carry;
|
|
if ( y1 < 0.0 ) {
|
|
y1 += 1.0;
|
|
carry = twoToMinus_48();
|
|
} else {
|
|
carry = 0.0;
|
|
}
|
|
randoms[11] = randoms[10];
|
|
randoms[10] = randoms[ 9];
|
|
randoms[ 9] = randoms[ 8];
|
|
randoms[ 8] = randoms[ 7];
|
|
randoms[ 7] = randoms[ 6];
|
|
randoms[ 6] = randoms[ 5];
|
|
randoms[ 5] = randoms[ 4];
|
|
randoms[ 4] = randoms[ 3];
|
|
randoms[ 3] = randoms[ 2];
|
|
randoms[ 2] = randoms[ 1];
|
|
randoms[ 1] = randoms[ 0];
|
|
randoms[ 0] = y1;
|
|
|
|
} else {
|
|
|
|
int m, nr, ns;
|
|
for ( m = 0, nr = 11, ns = 4; m < endIters; ++m, --nr ) {
|
|
y1 = randoms [ns] - randoms[nr] - carry;
|
|
if ( y1 < 0.0 ) {
|
|
y1 += 1.0;
|
|
carry = twoToMinus_48();
|
|
} else {
|
|
carry = 0.0;
|
|
}
|
|
randoms[nr] = y1;
|
|
--ns;
|
|
if ( ns < 0 ) {
|
|
ns = 11;
|
|
}
|
|
} // loop on m
|
|
|
|
double temp[12];
|
|
for (m=0; m<12; m++) {
|
|
temp[m]=randoms[m];
|
|
}
|
|
|
|
ns = 11 - endIters;
|
|
for (m=11; m>=0; --m) {
|
|
randoms[m] = temp[ns];
|
|
--ns;
|
|
if ( ns < 0 ) {
|
|
ns = 11;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Now when we return, there are 12 fresh usable numbers in s[11] ... s[0]
|
|
|
|
index = 12;
|
|
|
|
} // update()
|
|
|
|
void Ranlux64Engine::advance(int dozens) {
|
|
|
|
double y1, y2, y3;
|
|
double cValue = twoToMinus_48();
|
|
double zero = 0.0;
|
|
double one = 1.0;
|
|
|
|
// Technical note: We use Luscher's trick to only do the
|
|
// carry subtraction when we really have to. Like him, we use
|
|
// three registers instead of two so that we avoid sequences
|
|
// like storing y1 then immediately replacing its value:
|
|
// some architectures lose time when this is done.
|
|
|
|
// Luscher's ranlxd.c fills the stash going
|
|
// upward. We fill it downward to save a bit of time in the
|
|
// flat() routine at no cost later. This means that while
|
|
// Luscher's ir is jr+5, our n-r is (n-s)-5. (Note that
|
|
// though ranlxd.c initializes ir and jr to 11 and 7, ir as
|
|
// used is 5 more than jr because update is entered after
|
|
// incrementing ir.)
|
|
//
|
|
|
|
// I have CAREFULLY checked that the algorithms do match
|
|
// in all details.
|
|
|
|
int k;
|
|
for ( k = dozens; k > 0; --k ) {
|
|
|
|
y1 = randoms[ 4] - randoms[11] - carry;
|
|
|
|
y2 = randoms[ 3] - randoms[10];
|
|
if ( y1 < zero ) {
|
|
y1 += one;
|
|
y2 -= cValue;
|
|
}
|
|
randoms[11] = y1;
|
|
|
|
y3 = randoms[ 2] - randoms[ 9];
|
|
if ( y2 < zero ) {
|
|
y2 += one;
|
|
y3 -= cValue;
|
|
}
|
|
randoms[10] = y2;
|
|
|
|
y1 = randoms[ 1] - randoms[ 8];
|
|
if ( y3 < zero ) {
|
|
y3 += one;
|
|
y1 -= cValue;
|
|
}
|
|
randoms[ 9] = y3;
|
|
|
|
y2 = randoms[ 0] - randoms[ 7];
|
|
if ( y1 < zero ) {
|
|
y1 += one;
|
|
y2 -= cValue;
|
|
}
|
|
randoms[ 8] = y1;
|
|
|
|
y3 = randoms[11] - randoms[ 6];
|
|
if ( y2 < zero ) {
|
|
y2 += one;
|
|
y3 -= cValue;
|
|
}
|
|
randoms[ 7] = y2;
|
|
|
|
y1 = randoms[10] - randoms[ 5];
|
|
if ( y3 < zero ) {
|
|
y3 += one;
|
|
y1 -= cValue;
|
|
}
|
|
randoms[ 6] = y3;
|
|
|
|
y2 = randoms[ 9] - randoms[ 4];
|
|
if ( y1 < zero ) {
|
|
y1 += one;
|
|
y2 -= cValue;
|
|
}
|
|
randoms[ 5] = y1;
|
|
|
|
y3 = randoms[ 8] - randoms[ 3];
|
|
if ( y2 < zero ) {
|
|
y2 += one;
|
|
y3 -= cValue;
|
|
}
|
|
randoms[ 4] = y2;
|
|
|
|
y1 = randoms[ 7] - randoms[ 2];
|
|
if ( y3 < zero ) {
|
|
y3 += one;
|
|
y1 -= cValue;
|
|
}
|
|
randoms[ 3] = y3;
|
|
|
|
y2 = randoms[ 6] - randoms[ 1];
|
|
if ( y1 < zero ) {
|
|
y1 += one;
|
|
y2 -= cValue;
|
|
}
|
|
randoms[ 2] = y1;
|
|
|
|
y3 = randoms[ 5] - randoms[ 0];
|
|
if ( y2 < zero ) {
|
|
y2 += one;
|
|
y3 -= cValue;
|
|
}
|
|
randoms[ 1] = y2;
|
|
|
|
if ( y3 < zero ) {
|
|
y3 += one;
|
|
carry = cValue;
|
|
}
|
|
randoms[ 0] = y3;
|
|
|
|
} // End of major k loop doing 12 numbers at each cycle
|
|
|
|
} // advance(dozens)
|
|
|
|
void Ranlux64Engine::flatArray(const int size, double* vect) {
|
|
for( int i=0; i < size; ++i ) {
|
|
vect[i] = flat();
|
|
}
|
|
}
|
|
|
|
void Ranlux64Engine::setSeed(long seed, int lux) {
|
|
|
|
// The initialization is carried out using a Multiplicative
|
|
// Congruential generator using formula constants of L'Ecuyer
|
|
// as described in "A review of pseudorandom number generators"
|
|
// (Fred James) published in Computer Physics Communications 60 (1990)
|
|
// pages 329-344
|
|
|
|
const int ecuyer_a(53668);
|
|
const int ecuyer_b(40014);
|
|
const int ecuyer_c(12211);
|
|
const int ecuyer_d(2147483563);
|
|
|
|
const int lux_levels[3] = {109, 202, 397};
|
|
theSeed = seed;
|
|
|
|
if( (lux > 2)||(lux < 0) ){
|
|
pDiscard = (lux >= 12) ? (lux-12) : lux_levels[1];
|
|
}else{
|
|
pDiscard = lux_levels[luxury];
|
|
}
|
|
pDozens = pDiscard / 12;
|
|
endIters = pDiscard % 12;
|
|
|
|
long init_table[24];
|
|
long next_seed = seed;
|
|
long k_multiple;
|
|
int i;
|
|
next_seed &= 0xffffffff;
|
|
while( next_seed >= ecuyer_d ) {
|
|
next_seed -= ecuyer_d;
|
|
}
|
|
|
|
for(i = 0;i != 24;i++){
|
|
k_multiple = next_seed / ecuyer_a;
|
|
next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
|
|
- k_multiple * ecuyer_c;
|
|
if(next_seed < 0) {
|
|
next_seed += ecuyer_d;
|
|
}
|
|
next_seed &= 0xffffffff;
|
|
init_table[i] = next_seed;
|
|
}
|
|
// are we on a 64bit machine?
|
|
if( sizeof(long) >= 8 ) {
|
|
int64_t topbits1, topbits2;
|
|
#ifdef WIN32
|
|
topbits1 = ( (int64_t) seed >> 32) & 0xffff ;
|
|
topbits2 = ( (int64_t) seed >> 48) & 0xffff ;
|
|
#else
|
|
topbits1 = detail::rshift<32>(seed) & 0xffff ;
|
|
topbits2 = detail::rshift<48>(seed) & 0xffff ;
|
|
#endif
|
|
init_table[0] ^= topbits1;
|
|
init_table[2] ^= topbits2;
|
|
//std::cout << " init_table[0] " << init_table[0] << " from " << topbits1 << std::endl;
|
|
//std::cout << " init_table[2] " << init_table[2] << " from " << topbits2 << std::endl;
|
|
}
|
|
|
|
for(i = 0;i < 12; i++){
|
|
randoms[i] = (init_table[2*i ] ) * 2.0 * twoToMinus_32() +
|
|
(init_table[2*i+1] >> 15) * twoToMinus_48();
|
|
//if( randoms[i] < 0. || randoms[i] > 1. ) {
|
|
//std::cout << "setSeed: init_table " << init_table[2*i ] << std::endl;
|
|
//std::cout << "setSeed: init_table " << init_table[2*i+1] << std::endl;
|
|
//std::cout << "setSeed: random " << i << " is " << randoms[i] << std::endl;
|
|
//}
|
|
}
|
|
|
|
carry = 0.0;
|
|
if ( randoms[11] == 0. ) carry = twoToMinus_48();
|
|
// Perform an update before returning the first random number.
|
|
index = -1;
|
|
|
|
} // setSeed()
|
|
|
|
void Ranlux64Engine::setSeeds(const long * seeds, int lux) {
|
|
// old code only uses the first long in seeds
|
|
// setSeed( *seeds ? *seeds : 32767, lux );
|
|
// theSeeds = seeds;
|
|
|
|
// using code from Ranlux - even those are 32bit seeds,
|
|
// that is good enough to completely differentiate the sequences
|
|
|
|
const int ecuyer_a = 53668;
|
|
const int ecuyer_b = 40014;
|
|
const int ecuyer_c = 12211;
|
|
const int ecuyer_d = 2147483563;
|
|
|
|
const int lux_levels[3] = {109, 202, 397};
|
|
const long *seedptr;
|
|
|
|
theSeeds = seeds;
|
|
seedptr = seeds;
|
|
|
|
if(seeds == 0){
|
|
setSeed(theSeed,lux);
|
|
theSeeds = &theSeed;
|
|
return;
|
|
}
|
|
|
|
theSeed = *seeds;
|
|
|
|
// number of additional random numbers that need to be 'thrown away'
|
|
// every 24 numbers is set using luxury level variable.
|
|
|
|
if( (lux > 2)||(lux < 0) ){
|
|
pDiscard = (lux >= 12) ? (lux-12) : lux_levels[1];
|
|
}else{
|
|
pDiscard = lux_levels[luxury];
|
|
}
|
|
pDozens = pDiscard / 12;
|
|
endIters = pDiscard % 12;
|
|
|
|
long init_table[24];
|
|
long next_seed = *seeds;
|
|
long k_multiple;
|
|
int i;
|
|
|
|
for( i = 0;(i != 24)&&(*seedptr != 0);i++){
|
|
init_table[i] = *seedptr & 0xffffffff;
|
|
seedptr++;
|
|
}
|
|
|
|
if(i != 24){
|
|
next_seed = init_table[i-1];
|
|
for(;i != 24;i++){
|
|
k_multiple = next_seed / ecuyer_a;
|
|
next_seed = ecuyer_b * (next_seed - k_multiple * ecuyer_a)
|
|
- k_multiple * ecuyer_c;
|
|
if(next_seed < 0) {
|
|
next_seed += ecuyer_d;
|
|
}
|
|
next_seed &= 0xffffffff;
|
|
init_table[i] = next_seed;
|
|
}
|
|
}
|
|
|
|
for(i = 0;i < 12; i++){
|
|
randoms[i] = (init_table[2*i ] ) * 2.0 * twoToMinus_32() +
|
|
(init_table[2*i+1] >> 15) * twoToMinus_48();
|
|
}
|
|
|
|
carry = 0.0;
|
|
if ( randoms[11] == 0. ) carry = twoToMinus_48();
|
|
// Perform an update before returning the first random number.
|
|
index = -1;
|
|
|
|
}
|
|
|
|
void Ranlux64Engine::saveStatus( const char filename[] ) const
|
|
{
|
|
std::ofstream outFile( filename, std::ios::out ) ;
|
|
if (!outFile.bad()) {
|
|
outFile << "Uvec\n";
|
|
std::vector<unsigned long> v = put();
|
|
for (unsigned int i=0; i<v.size(); ++i) {
|
|
outFile << v[i] << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void Ranlux64Engine::restoreStatus( const char filename[] )
|
|
{
|
|
std::ifstream inFile( filename, std::ios::in);
|
|
if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
|
|
std::cerr << " -- Engine state remains unchanged\n";
|
|
return;
|
|
}
|
|
if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
|
|
std::vector<unsigned long> v;
|
|
unsigned long xin;
|
|
for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
|
|
inFile >> xin;
|
|
if (!inFile) {
|
|
inFile.clear(std::ios::badbit | inFile.rdstate());
|
|
std::cerr << "\nJamesRandom state (vector) description improper."
|
|
<< "\nrestoreStatus has failed."
|
|
<< "\nInput stream is probably mispositioned now." << std::endl;
|
|
return;
|
|
}
|
|
v.push_back(xin);
|
|
}
|
|
getState(v);
|
|
return;
|
|
}
|
|
|
|
if (!inFile.bad() && !inFile.eof()) {
|
|
// inFile >> theSeed; removed -- encompased by possibleKeywordInput
|
|
for (int i=0; i<12; ++i) {
|
|
inFile >> randoms[i];
|
|
}
|
|
inFile >> carry; inFile >> index;
|
|
inFile >> luxury; inFile >> pDiscard;
|
|
pDozens = pDiscard / 12;
|
|
endIters = pDiscard % 12;
|
|
}
|
|
}
|
|
|
|
void Ranlux64Engine::showStatus() const
|
|
{
|
|
std::cout << std::endl;
|
|
std::cout << "--------- Ranlux engine status ---------" << std::endl;
|
|
std::cout << " Initial seed = " << theSeed << std::endl;
|
|
std::cout << " randoms[] = ";
|
|
for (int i=0; i<12; ++i) {
|
|
std::cout << randoms[i] << std::endl;
|
|
}
|
|
std::cout << std::endl;
|
|
std::cout << " carry = " << carry << ", index = " << index << std::endl;
|
|
std::cout << " luxury = " << luxury << " pDiscard = "
|
|
<< pDiscard << std::endl;
|
|
std::cout << "----------------------------------------" << std::endl;
|
|
}
|
|
|
|
std::ostream & Ranlux64Engine::put( std::ostream& os ) const
|
|
{
|
|
char beginMarker[] = "Ranlux64Engine-begin";
|
|
os << beginMarker << "\nUvec\n";
|
|
std::vector<unsigned long> v = put();
|
|
for (unsigned int i=0; i<v.size(); ++i) {
|
|
os << v[i] << "\n";
|
|
}
|
|
return os;
|
|
}
|
|
|
|
std::vector<unsigned long> Ranlux64Engine::put () const {
|
|
std::vector<unsigned long> v;
|
|
v.push_back (engineIDulong<Ranlux64Engine>());
|
|
std::vector<unsigned long> t;
|
|
for (int i=0; i<12; ++i) {
|
|
t = DoubConv::dto2longs(randoms[i]);
|
|
v.push_back(t[0]); v.push_back(t[1]);
|
|
}
|
|
t = DoubConv::dto2longs(carry);
|
|
v.push_back(t[0]); v.push_back(t[1]);
|
|
v.push_back(static_cast<unsigned long>(index));
|
|
v.push_back(static_cast<unsigned long>(luxury));
|
|
v.push_back(static_cast<unsigned long>(pDiscard));
|
|
return v;
|
|
}
|
|
|
|
std::istream & Ranlux64Engine::get ( std::istream& is )
|
|
{
|
|
char beginMarker [MarkerLen];
|
|
is >> std::ws;
|
|
is.width(MarkerLen); // causes the next read to the char* to be <=
|
|
// that many bytes, INCLUDING A TERMINATION \0
|
|
// (Stroustrup, section 21.3.2)
|
|
is >> beginMarker;
|
|
if (strcmp(beginMarker,"Ranlux64Engine-begin")) {
|
|
is.clear(std::ios::badbit | is.rdstate());
|
|
std::cerr << "\nInput stream mispositioned or"
|
|
<< "\nRanlux64Engine state description missing or"
|
|
<< "\nwrong engine type found." << std::endl;
|
|
return is;
|
|
}
|
|
return getState(is);
|
|
}
|
|
|
|
std::string Ranlux64Engine::beginTag ( ) {
|
|
return "Ranlux64Engine-begin";
|
|
}
|
|
|
|
std::istream & Ranlux64Engine::getState ( std::istream& is )
|
|
{
|
|
if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
|
|
std::vector<unsigned long> v;
|
|
unsigned long uu;
|
|
for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
|
|
is >> uu;
|
|
if (!is) {
|
|
is.clear(std::ios::badbit | is.rdstate());
|
|
std::cerr << "\nRanlux64Engine state (vector) description improper."
|
|
<< "\ngetState() has failed."
|
|
<< "\nInput stream is probably mispositioned now." << std::endl;
|
|
return is;
|
|
}
|
|
v.push_back(uu);
|
|
}
|
|
getState(v);
|
|
return (is);
|
|
}
|
|
|
|
// is >> theSeed; Removed, encompassed by possibleKeywordInput()
|
|
|
|
char endMarker [MarkerLen];
|
|
for (int i=0; i<12; ++i) {
|
|
is >> randoms[i];
|
|
}
|
|
is >> carry; is >> index;
|
|
is >> luxury; is >> pDiscard;
|
|
pDozens = pDiscard / 12;
|
|
endIters = pDiscard % 12;
|
|
is >> std::ws;
|
|
is.width(MarkerLen);
|
|
is >> endMarker;
|
|
if (strcmp(endMarker,"Ranlux64Engine-end")) {
|
|
is.clear(std::ios::badbit | is.rdstate());
|
|
std::cerr << "\nRanlux64Engine state description incomplete."
|
|
<< "\nInput stream is probably mispositioned now." << std::endl;
|
|
return is;
|
|
}
|
|
return is;
|
|
}
|
|
|
|
bool Ranlux64Engine::get (const std::vector<unsigned long> & v) {
|
|
if ((v[0] & 0xffffffffUL) != engineIDulong<Ranlux64Engine>()) {
|
|
std::cerr <<
|
|
"\nRanlux64Engine get:state vector has wrong ID word - state unchanged\n";
|
|
return false;
|
|
}
|
|
return getState(v);
|
|
}
|
|
|
|
bool Ranlux64Engine::getState (const std::vector<unsigned long> & v) {
|
|
if (v.size() != VECTOR_STATE_SIZE ) {
|
|
std::cerr <<
|
|
"\nRanlux64Engine get:state vector has wrong length - state unchanged\n";
|
|
return false;
|
|
}
|
|
std::vector<unsigned long> t(2);
|
|
for (int i=0; i<12; ++i) {
|
|
t[0] = v[2*i+1]; t[1] = v[2*i+2];
|
|
randoms[i] = DoubConv::longs2double(t);
|
|
}
|
|
t[0] = v[25]; t[1] = v[26];
|
|
carry = DoubConv::longs2double(t);
|
|
index = v[27];
|
|
luxury = v[28];
|
|
pDiscard = v[29];
|
|
return true;
|
|
}
|
|
|
|
} // namespace CLHEP
|