//****************************************************************************** //** SCATMECH: Polarized Light Scattering C++ Class Library //** //** File: random.cpp //** //** Thomas A. Germer //** Sensor Science Division, National Institute of Standards and Technology //** 100 Bureau Dr. Stop 8443; Gaithersburg, MD 20899-8443 //** Phone: (301) 975-2876 //** Email: thomas.germer@nist.gov //** //****************************************************************************** #include "random.h" #include #include "scatmech.h" #include "matrixmath.h" #include #include "fft.h" #if _MSC_VER > 1 #include #else #include #include #endif using namespace std; namespace SCATMECH { // The code for UNIrand was taken from the CMLIB library and adapted to C++ by T.A. Germer // The header information is given below: //C***BEGIN PROLOGUE UNI //C***DATE WRITTEN 810915 //C***REVISION DATE 830805 //C***CATEGORY NO. L6A21 //C***KEYWORDS RANDOM NUMBERS, UNIFORM RANDOM NUMBERS //C***AUTHOR BLUE, JAMES, SCIENTIFIC COMPUTING DIVISION, NBS //C KAHANER, DAVID, SCIENTIFIC COMPUTING DIVISION, NBS //C MARSAGLIA, GEORGE, COMPUTER SCIENCE DEPT., WASH STATE UNIV //C //C***PURPOSE THIS ROUTINE GENERATES QUASI UNIFORM RANDOM NUMBERS ON [0,1 //C AND CAN BE USED ON ANY COMPUTER WITH WHICH ALLOWS INTEGERS //C AT LEAST AS LARGE AS 32767. //C***DESCRIPTION //C //C THIS ROUTINE GENERATES QUASI UNIFORM RANDOM NUMBERS ON THE INTER //C [0,1). IT CAN BE USED WITH ANY COMPUTER WHICH ALLOWS //C INTEGERS AT LEAST AS LARGE AS 32767. //C //C //C USE //C FIRST TIME.... //C Z = UNI(JD) //C HERE JD IS ANY N O N - Z E R O INTEGER. //C THIS CAUSES INITIALIZATION OF THE PROGRAM //C AND THE FIRST RANDOM NUMBER TO BE RETURNED AS Z. //C SUBSEQUENT TIMES... //C Z = UNI(0) //C CAUSES THE NEXT RANDOM NUMBER TO BE RETURNED AS Z. //C //C //C.................................................................. //C NOTE: USERS WHO WISH TO TRANSPORT THIS PROGRAM FROM ONE COMPUTER //C TO ANOTHER SHOULD READ THE FOLLOWING INFORMATION..... //C //C MACHINE DEPENDENCIES... //C MDIG = A LOWER BOUND ON THE NUMBER OF BINARY DIGITS AVAILABLE //C FOR REPRESENTING INTEGERS, INCLUDING THE SIGN BIT. //C THIS VALUE MUST BE AT LEAST 16, BUT MAY BE INCREASED //C IN LINE WITH REMARK A BELOW. //C //C REMARKS... //C A. THIS PROGRAM CAN BE USED IN TWO WAYS: //C (1) TO OBTAIN REPEATABLE RESULTS ON DIFFERENT COMPUTERS, //C SET 'MDIG' TO THE SMALLEST OF ITS VALUES ON EACH, OR, //C (2) TO ALLOW THE LONGEST SEQUENCE OF RANDOM NUMBERS TO BE //C GENERATED WITHOUT CYCLING (REPEATING) SET 'MDIG' TO THE //C LARGEST POSSIBLE VALUE. //C B. THE SEQUENCE OF NUMBERS GENERATED DEPENDS ON THE INITIAL //C INPUT 'JD' AS WELL AS THE VALUE OF 'MDIG'. //C IF MDIG=16 ONE SHOULD FIND THAT //C THE FIRST EVALUATION //C Z=UNI(305) GIVES Z=.027832881... //C THE SECOND EVALUATION //C Z=UNI(0) GIVES Z=.56102176... //C THE THIRD EVALUATION //C Z=UNI(0) GIVES Z=.41456343... //C THE THOUSANDTH EVALUATION //C Z=UNI(0) GIVES Z=.19797357... //C //C***REFERENCES MARSAGLIA G., "COMMENTS ON THE PERFECT UNIFORM RANDOM //C NUMBER GENERATOR", UNPUBLISHED NOTES, WASH S. U. //C***ROUTINES CALLED I1MACH,XERROR //C***END PROLOGUE UNI namespace CMLIB { UNIrand::UNIrand() { M[0]=30788; M[1]=23052; M[2]=2053; M[3]=19346; M[4]=10646; M[5]=19427; M[6]=23975; M[7]=19049; M[8]=10949; M[9]=19693; M[10]=29746; M[11]=26748; M[12]=2796; M[13]=23890; M[14]=29168; M[15]=31924; M[16]=16499; I=5; J=17; M1=32767; M2=256; seeded=false; } void UNIrand::seed(int JD) { int MDIG = numeric_limits::digits+1; if (MDIG < 16) throw SCATMECH_exception("UNI--MDIG LESS THAN 16"); M1= (1<<(MDIG-2)) + ((1<<(MDIG-2))-1); M2 = (1<<(MDIG/2)); int iabsJD = abs(JD); int JSEED = iabsJD(xmin,1.)); distrib.push_back(std::pair(xmax,1.)); return Table(distrib); } Table Random_Number::normal(double stdev, int npoints, double nstdev) { Table::VECTOR normal; for (int i=0; i(x,y)); } return Table(normal); } /*Table Random_Number::linear(double xmax, int npoints) { Table::VECTOR prob; for (int i=0;i(x,y)); } return Table(prob); }*/ /*Table Random_Number::squared(double xmax, int npoints) { Table::VECTOR prob; for (int i=0;i(x,y)); } return Table(prob); }*/ Table Random_Number::sinesqr(int npoints) { Table::VECTOR prob; for (int i=0; i(x,y)); } return Table(prob); } Table Random_Number::exponential(double decay, int npoints,double ndecay) { SCATMECH::Table::VECTOR exponential; for (int i=0; i(x,y)); } return Table(exponential); } Table Random_Number::log_normal(double mode, double stdev, int npoints, double nstdev) { SCATMECH::Table::VECTOR log_normal; double log10mode = log10(mode); for (int i=0; i(x,y)); } return Table(log_normal); } double Random_Number::operator()() { return lookup.value(rand()); } double Random_Number::operator()(double offset) { double r = rand(); if (rfirst; double y=distrib.get_table().begin()->second; temp.push_back(std::pair(0.,x)); SCATMECH::Table::VECTOR::const_iterator cp; for (cp=distrib.get_table().begin(),++cp; cpfirst - x; integral += (cp->second + y)/2.*dx; x = cp->first; y = cp->second; temp.push_back(std::pair(integral,x)); } SCATMECH::Table::VECTOR::iterator p; for (p=temp.begin(); pfirst /= integral; } lookup = Table(temp); } void Random_Number::initialize() { set_seed(-(int)time(NULL)+(seed_add+=seed_adder)); } int Random_Number::seed_add=12345; int CMLIB::UNIrand::seed_add=123456; namespace { int mygetpid() { #if _MSC_VER > 1000 int result =_getpid(); #else int result = getpid(); #endif return result; } } int Random_Number::seed_adder=594*mygetpid(); int CMLIB::UNIrand::seed_adder=594*mygetpid(); Multivariate_Random_Number::Multivariate_Random_Number() { random = Random_Number::normal(); N=0; } Multivariate_Random_Number::Multivariate_Random_Number(int n, const std::vector& covmatrix) { N=n; random = Random_Number::normal(); if (covmatrix.size()!=n*n) throw SCATMECH_exception("Invalid size for covariance matrix"); vector cov(n*n); for (int i=0; i& values) { values.resize(N); for (int i=0; i fC(N); vector f(N); vector fx(N); int i; double dx = period/N; // // Create self-affine autocorrelation function... // for (i=0; i