20 July, 2008 - beta version.
Copyright (C) 2008: R B Davies
This is a C++ library for generating sequences of pseudo-random numbers from a wide variety of distributions. It is particularly appropriate for the situation where one requires sequences of identically distributed random numbers since the set up time for each type of distribution is relatively long but it is efficient when generating each new random number. The library includes classes for generating random numbers from a number of distributions and is easily extended to be able to generate random numbers from almost any of the standard distributions.
There have been substantial changes from newran02 in the way seeds are handled. See the section on program organisation if you are upgrading.
You need to read the section on program organisation even if you are not upgrading.
Comments and bug reports to robert at statsresearch.co.nz [replace at by you-know-what].
For updates and notes see http://www.robertnz.net.
There are no restrictions on the use of newran except that I take no liability for any problems that may arise from its use.
I welcome its distribution as part of low cost CD-ROM collections.
You can use it in your commercial projects. However, if you distribute the source, please make it clear which parts are mine and that they are available essentially for free over the Internet.
The following are the classes for generating random numbers from particular distributions
Uniform | uniform distribution |
Constant | return a constant |
Exponential | negative exponential distribution |
Cauchy | Cauchy distribution |
Normal | normal distribution |
ChiSq | non-central chi-squared distribution |
Gamma | gamma distribution |
Pareto | Pareto distribution |
Poisson | Poisson distribution |
Binomial | binomial distribution |
NegativeBinomial | negative binomial distribution |
Stable | stable family of distributions |
The following classes are available to the user for generating numbers from other distributions
PosGenX | Positive random numbers with a decreasing density |
SymGenX | Random numbers from a symmetric unimodal density |
AsymGenX | Random numbers from an asymmetric unimodal density |
PosGen | Positive random numbers with a decreasing density |
SymGen | Random numbers from a symmetric unimodal density |
AsymGen | Random numbers from an asymmetric unimodal density |
DiscreteGen | Random numbers from a discrete distribution |
SumRandom | Sum and/or product of random numbers |
MixedRandom | Mixture of random numbers |
Each of these classes has the following member functions
Real Next() | Get a new random number |
char* Name() | Name of the distribution |
ExtReal Mean() | Mean of the distribution |
ExtReal Variance() | Variance of the distribution |
These 4 functions are declared virtual so it is easy to write simulation programs that can be run with different distributions.
Real is typedefed to be either float or double. See customising. Note that Next() always returns a Real even for discrete distributions.
ExtReal is a class which is, in effect either a Real or one of the following: PlusInfinity, MinusInfinity, Indefinite or Missing. I use ExtReal so that I can return infinite or indefinite values for the mean or variance of a distribution.
There are two classes for doing combinations and permutations.
RandomPermutation | Draw numbers without replacement |
RandomCombination | Draw numbers without replacement and sort |
There are three classes for generating random numbers where we want to vary the parameters at each call. It would be inefficient to use the previous classes since you would need to set up a random number object at each call.
VariPoisson | Poisson distribution |
VariBinomial | Binomial distribution |
VariLogNormal | Log normal distribution |
The following classes are for accessing different uniform random number generators
LGM_simple | Lewis-Goodman-Miller generator |
LGM_mixed | Lewis-Goodman-Miller generator with Marsaglia mixing |
WH | Wichmann Hill generator |
FM | Fishman Moore generator |
MotherOfAll | Marsaglia's mother of all generators |
MultWithCarry | Marsaglia's multiply with carry generator |
MT | Mersenne Twister generator |
Further details of all these classes including the constructors are given below.
A reference for the kind of methods used in this program is Automatic Nonuniform Random Variate Generation by Wolfgang Hörmann, Josef Leydold and Gerhard Derflinger published by Springer in 2003.
The file include.h sets a variety of options including several compiler dependent options. You may need to edit include.h to get the options you require. If you are using a compiler different from one I have worked with you may have to set up a new section in include.h appropriate for your compiler.
Borland, Gnu, and Microsoft are recognised automatically. If none of these are recognised a default set of options is used. These are fine for Intel and Sun C++. If you using a compiler I don't know about, you may have to write a new set of options.
There is an option in include.h for selecting whether you use compiler supported exceptions, simulated exceptions, or disable exceptions. Use the option for compiler supported exceptions if and only if you have set the option on your compiler to recognise exceptions. Disabling exceptions sometimes helps with compilers that are incompatible with my exception simulation scheme. The default is compiler supported exceptions and I suggest you don't change this if you are using a modern compiler.
Newran does not do memory clean-up with the simulated exceptions. |
Activate the appropriate statement to make the element type Real to mean float or double (the default is double and I recommend you leave it as double).
Activate the standard option if you want to use the form of include statements specified in the standard - this is now done implicitly for recent versions of most of the compilers I know about.
Activate the namespace option if you want the newran classes in be placed in namespace NEWRAN.
You may get a tiny increase in speed if your compiler has the unsigned int64 type and you enable the line that defines HAS_INT64.
You may need to comment out the line defining TypeDefException if you are using Borland Builder 6 in GUI mode.
The other options are for my newmat matrix library and are not relevant to newran.
You will need to compile newran1.cpp, newran2.cpp, myexcept.cpp, simpstr.cpp, myexcept.cpp and extreal.cpp and link the resulting object files to your programs. Your source files which access newran will need to have newran.h as an include file.
I have tested newran03 with the following compilers (all PC ones in 32 bit console mode)
Borland 5.6, 5.8 | OK |
Microsoft 6.0, 7.0, 7.1,8 | OK |
Open Watcom 1.7a | Test programs fail to compile |
Sun CC | OK |
Gnu G++ 3.4, 4.0,4.1 | OK |
Intel for Windows 10 | OK |
Intel for Linux 10 | OK |
I have included make files for Borland 5.5, 5.6, Microsoft Visual C++, Intel C++ for Windows and Linux, CC and Gnu G++ for compiling the test and example programs. See files section. These have been generated with my genmake program. There are notes on using these make files in the genmake documentation (copy from http://www.robertnz.net).
This is the main documentation file. However, I have also started including comments in the code that can be interpreted by the Doxygen documentation system. I suggest you set Doxygen options
The random number generator needs to be set up at the beginning of your program. This involves declaring a uniform random number generator, registering it as the one to be used for generating your random numbers and setting up the initial seed value.
The seed is a block of data which the generator updates each time a new random number is requested and uses to generate the new random number.
The seed needs to be initiated before any random numbers are called. Newran lets you copy the value of the seed to disk at the end of your program and reload it the next time your program runs so you get a new set of random numbers for each run of your program (this won't work, of course if you are running more than program using the random number generator at the same time). Alternatively you can use a default value of the seed, in which case you get the same set of random numbers each time. Or the program allows you to update part of the seed at each run so you will probably get a new set of numbers but there is a chance of getting a rerun of some of your old numbers.
If you wish to use the default seed your program should begin like this:
MotherOfAll urng; // declare uniform random number generator Random::Set(urng); // set urng as generator to be used Normal normal; // declare normal generator for (int i = 1; i <= 10; ++i) // print 10 normal random numbers cout << setprecision(5) << setw(10) << normal.Next() << endl;
Here we are using the MotherOfAll generator. See the section on uniform random number generators for a description of all the generators available in newran. Our program finishes with the code for generating an printing 10 standard normal random numbers.
If you want to vary the starting seed but don't want to use to process of copying the seed to disk you can replace the first line with
MotherOfAll urng(s); // declare uniform random number generator
where s is a double strictly between 0 and 1. You will need to enter a new value of s each time your program is run.
If you want to store the seed to disk use a program like
// put the next four lines near the beginning of your main program so they get // called only once Random::SetDirectory("c:\\seed\\"); // set directory for seed control MotherOfAll urng; // declare uniform random number generator Random::Set(urng); // set urng as generator to be used Random::CopySeedFromDisk(true); // get seed information from disk Normal normal; // declare normal generator for (int i = 1; i <= 10; ++i) // print 10 normal random numbers cout << setprecision(5) << setw(10) << normal.Next() << endl;
The first line declares the directory in which the seeds are to be stored. You will need to create this directory and copy the files fm.txt, lgm.txt, lgm_mixed.txt, mother.txt, mt19937.txt, multwc.txt, wh.txt from the newran distribution files to this directory. My example is for MS Windows. Note the double back slashes including the double back slash at the end. For Unix use something like "/home/robert/seed/". The CopySeedFromDisk statement gets the seed data from disk. With the argument true the seed data on disk will be automatically updated when the random number generator's destructor is called as your program ends. If you don't want that use the argument false. There is also a CopySeedToDisk function that can used to update the seed data on disk. See the section about class Random.
If a function in Newran detects an error it will throw an exception. It is important that your program can catch this exception - otherwise most compilers return an incomprehensible error message. I suggest you surround your main program by a Try - Catch block. See nr_ex.cpp as an example. For more information on my use of exceptions see the newmat documentation on my website.
There are three test programs and one example program.
All these programs have a statement
bool copy_seed_from_disk = false;
With this statement the random number generators use the default seed so that the results can be compared with the sample outputs. Replace false by true to use seed values copied from disk.
This example generates and prints 10 normal random numbers. You need file nr_ex.cpp as well as the newran program files.
The files tryrand.cpp, tryrand1.cpp, tryrand2.cpp, tryrand3.cpp, tryrand4.cpp, tryrand5.cpp, tryrand6.cpp, format.cpp, str.cpp, utility.cpp, test_out.cpp run the generators in the library and print histograms of the resulting distributions. Sample means and variances are also calculated and can be compared with the population values. The results from one of my test runs are in tryrand.txt. Other compilers may give different but still correct results. This is most likely due to different round-off error but may also be due to different order of evaluation of expressions. The appearance of the histograms in the output should be similar to that in tryrand.txt and the statistical tests should still be passed. I use * to denote statistical significance at the 5% level, ** for 1% and *** for 0.1%. We are carrying out quite a lot of tests so you will see * from time to time, ** occasionally and *** very occasionally. The last column in the tests shows -log10 of the significance level. So 2 corresponds to 1% significance. One should suspect a problem if you see a value of 4 or above or more than the occasional value of 2 or above. There are some notes in tryrand.txt for assessing the output.
You get a lot of small differences in the tests of the stable generator. Most of these look like round-off error, suggesting that the calculations are numerically a little unstable, possibly because of the large numbers that can sometimes be generated.
The test program tryrand.cpp includes a simple test for memory leaks. This is valid for only some compilers. It seems to work for Borland C++ in console mode but not for some versions of Gnu G++ or Microsoft C++.
You can edit tryrand.cpp to change the uniform random number generator used and to decide whether to use the default starting value for the seed or read it from disk.
The files tryurng.cpp, tryurng1.cpp, format.cpp, str.cpp, utility.cpp, test_out.cpp are for testing the uniform random number generators. Edit tryurng.cpp to change the sample size and to decide whether to use the default starting value for the seed or read it from disk. With the default starting value for the seed and a sample size of 10 million you should get identical results to those in tryurng.txt except for the times and memory locations. I use * to denote statistical significance at the 5% level, ** for 1% and *** for 0.1%. We are carrying out quite a lot of tests so you will see * from time to time, ** occasionally and *** very occasionally. The last column in the tests shows -log10 of the significance level. So 2 corresponds to 1% significance. One should suspect a problem if you see a value of 4 or above or more than the occasional value of 2 or above.
These tests are not intended to replace the Diehard tests - rather they are a limited number of tests directed at the most significant bits of the random number that allow me to vary the sample size and run in a reasonable time and with a reasonable mount of memory. More comprehensive testing would require a rather larger set of tests.
With a sample size of 10 million all the generators pass the tests; with a sample size of 100 million the stars come out for the first three generators. The others pass with a sample size of 5000 million.
Here are the details of the tests:
Mean | Test mean of numbers |
Variance | Test variance of numbers |
AutoCov 1 | Test auto-covariance of adjacent numbers |
Chi 4 | Chi-squared test of uniformity of top 4 bits |
Chi 8 | Chi-squared test of uniformity of top 8 bits |
Chi 16 | Chi-squared test of uniformity of top 16 bits |
MM 0-4-2 | Marsaglia monkey of top 4 bits, 2 words at a time |
MM 0-8-2 | Marsaglia monkey of top 8 bits, 2 words at a time |
MM 0-1-8 | Marsaglia monkey of top bit, 8 words at a time |
MM 0-1-16 | Marsaglia monkey of top bit, 16 words at a time |
MM sparse | Marsaglia sparse occupancy test of top bit, number of words depends on sample size |
For more details on the Marsaglia tests see "Marsaglia, G. and Zaman, A., 1993, Monkey tests for random number generators, Computers and Mathematics with Applications 26, 9, 1-10". You should be able to find a copy of this with a Google search.
The file geturng.cpp is for generating a file to be analysed with the Diehard tests. Edit this file to select the generator and whether to use the full 32 bits from the generators or to assemble the words from the top 8 bits.
The file test_lg.cpp is for testing the log gamma function. Your output should be similar to test_lg.txt but probably won't be identical.
You can choose from the generators described in this section. Ideally you should repeat your simulations with more than one generator. My order of preference - without any really good evidence about the first four - is
If you take the output from the generators as 32 bit words (use ulNext()) then the first 4 generators pass the Diehard tests. The last 3 generators generate 31 bit words with the lowest order bit in a 32 bit word being set to zero. If you ignore the Diehard tests that use the lowest order bit then these generators also pass. If you generate the data for the Diehard tests by taking only the top 8 bits from each word from the generator and assembling them into 32 bit words then the first 6 generators pass but the last one fails.
If you apply the simple tests in my tryurng program all generators pass with 10 million words from the generator. With 100 million calls the last three fail but with the mixed LGM generator doing better than the other two. The first four pass with 5000 million calls.
Each of the uniform random number generator classes has the following member functions
constructor(Real seed) | Constructor with optional starting seed |
Real Next() | Get a new random number |
unsigned long ulNext() | New random number as unsigned long |
char* Name() | Name of the generator |
This is included for historical interest only - do not use this generator for serious work. You can find a description of it in Numerical Recipes in C by Press, Flannery, Teukolsky, Vetterling published by the Cambridge University Press.
This was the generator used in newran02. It uses Marsaglia's mixing method to improve the performance of the Lewis-Goodman Miller generator. Alternate numbers from the generator are used for the actual random number and the mixing process. Do not use this generator if your simulation requires more than 10 million calls to the generator.
See B.A. Wichmann and I. D. Hill (1982). Algorithm AS 183: An Efficient and Portable Pseudo-random Number Generator, Applied Statistics, 31, 188-190; Remarks: 34, p.198 and 35, p.89.
See G.S. Fishman and L.R. Moore (1986), An exhaustive analysis of multiplicative congruential random number generators with modulus 2^31-1, SIAM J Sci. Stat. Comput., 7, pp. 24-45. Do not use this generator if your simulation requires more than 10 million calls to the generator.
I copied this code from http://www.taygeta.com/random.xml.
Marsaglia described this method in
From: George Marsaglia <geo@stat.fsu.edu>
Subject: A very fast and very good random number generator
Date: 1998/01/30
See http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=34D263C0.354E67F0%40stat.fsu.edu
I copied this code from http://www.math.keio.ac.jp/matumoto/emt.html.
This is the base of the other random number classes. I suggest you don't use it directly. There are four static functions for initialising the random number generator and manipulating the seeds.
void Random::Set(Random& r) | Select the uniform random number generator |
void Random::CopySeedFromDisk(bool update=false) | Copy the seed from disk (update=true to copy to seed to disk when the generator is destructed) |
void Random::CopySeedToDisk() | Copy the current value of the seed to disk |
void Random::SetDirectory(const char* dir) | Directory where seeds are to be held (terminate with / or \\) |
Return a uniform random number from the range (0, 1). The constructor has no parameters. For example
Uniform U; for (int i=0; i<100; i++) cout << U.Next() << "\n";
prints a column of 100 numbers drawn from a uniform distribution.
This returns a constant. The constructor takes one Real parameter; the value of the constant to be returned. So
Constant C(5.5); cout << C.Next() << "\n";
prints 5.5.
This generates random numbers with density exp(-x) for x>=0. The constructor takes no arguments.
Exponential E; for (int i=0; i<100; i++) cout << E.Next() << "\n";
Generates random numbers from a standard Cauchy distribution. The constructor takes no parameters.
Cauchy C; for (int i=0; i<100; i++) cout << C.Next() << "\n";
Generates standard normal random numbers. The constructor has no arguments. This class has been augmented to ensure only one copy of the arrays generated by the constructor exist at any given time. That is, if the constructor is called twice (before the destructor is called) only one copy of the arrays is generated.
Normal Z; for (int i=0; i<100; i++) cout << Z.Next() << "\n";
Non-Central chi-squared distribution. The method uses ChiSq1 to generate the non-central part and Gamma2 or Exponential to generate the central part. The constructor takes as arguments the number of degrees of freedom (>=1) and the non-centrality parameter (omit if zero).
int df = 10; Real noncen = 2.0; ChiSq CS(df, noncen); for (int i=0; i<100; i++) cout << CS.Next() << "\n";
Gamma distribution. The constructor takes the shape parameter as argument. Uses Gamma1, Gamma2 or Exponential.
Real shape = 0.75; Gamma G(shape); for (int i=0; i<100; i++) cout << G.Next() << "\n";
Pareto distribution. The constructor takes the shape parameter as argument. I follow the definition of Kotz and Johnson's Continuous univariate distributions 1, chapter 19, page 234, with k = 1. The generator uses a power transform of a uniform random number.
Real shape = 0.75; Pareto P(shape); for (int i=0; i<100; i++) cout << P.Next() << "\n";
Poisson distribution: uses Poisson1 or Poisson2. Constructor takes the mean as its argument.
Real mean = 5.0; Poisson P(mean); for (int i=0; i<100; i++) cout << (int)P.Next() << "\n";
Binomial distribution: uses Binomial1 or Binomial2. Constructor takes n and p as its arguments.
int n = 50; Real p = 0.25; Binomial B(n, p); for (int i=0; i<100; i++) cout << (int)B.Next() << "\n";
Negative binomial distribution. Constructor takes N and P as its arguments. I use the notation of Kotz and Johnson's Discrete distributions. Some people use p = 1/(P+1) in place of the second parameter.
Real N = 12.5; Real P = 3.0; NegativeBinomial NB(N, P); for (int i=0; i<100; i++) cout << (int)NB.Next() << "\n";
Stable family of distributions. I use the method of Chambers, J.M., Mallows, C. & Stuck, B.W. (1976): A Method for simulating stable random variables. Journal of the American Statistical Association 71, 340-344.
The constructor takes alpha, beta and notation as its arguments where 0 < alpha ≤ 2, -1 ≤ beta ≤ 1 and notation is one of Stable::Kalpha, Stable::Standard or Stable::Chambers.
Real alpha = 0.75, beta = 0.5; Stable stable(alpha, beta, Stable::Chambers); for (int i=0; i<100; i++) cout << stable.Next() << "\n";
The method becomes unreliable for small values of alpha. Best keep alpha > 0.2.
The notation parameter determines the version of the definition of the stable distribution. Here are the characteristic functions corresponding to the first two versions (α ≠ 1).
Kalpha: This is the version used by Chambers et al at the beginning of their paper.
α exp[-|u| exp{½ π i β k(α) sign(u)}]
where k(α) = 1 - |1 - α|.
Standard: this is the notation most commonly used
α exp[-|u| {1 - i β tan(½ π β) sign(u)}]
Chambers: The Chambers version is the same as the Standard version except that β tan(½ π α) is subtracted from the result (α ≠ 1). This is the version used in the S-plus statistical package.
In all cases the same version is used when α = 1:
exp[-|u| {1 + 2 i β ln|u| sign(u) / π}]
The notation is irrelevant when α = 1 or 2 or when β = 0 and in these cases the notation argument can be omitted.
This uses an arbitrary density for generating random numbers from that density.
PosGenX supposes that
Suppose Real pdf(Real) is the density. Then use pdf as the argument of the constructor. For example
PosGenX P(pdf); for (int i=0; i<100; i++) cout << P.Next() << "\n";
Note that the probability density pdf must drop to exactly 0 for the argument large enough. For example, include a statement in the program for pdf that, if the value is less than 1.0E-15, then return 0. |
SymGenX supposes that
This corresponds to PosGenX for symmetric distributions.
Note that the probability density pdf must drop to exactly 0 for the argument large enough. For example, include a statement in the program for pdf that, if the value is less than 1.0E-15, then return 0. |
Corresponds to PosGenX for unimodal distributions.
AsymGenX supposes that
The arguments of the constructor are the name of the density function and the location of the mode.
Real pdf(Real); Real mode; ..... AsymGenX X(pdf, mode); for (int i=0; i<100; i++) cout << X.Next() << "\n";
Note that the probability density pdf must drop to exactly 0 for the argument large (large positive and large negative) enough. For example, include a statement in the program for pdf that, if the value is less than 1.0E-15, then return 0. |
PosGen is not used directly. It is used as a base class for generating a random number from an arbitrary probability density p(x). p(x) must be non-zero only for x>=0, be monotonically decreasing for x>=0, and be finite. For example, p(x) could be exp(-x) for x>=0.
The method is to cover the density in a set of rectangles of equal area as in the diagram (indicated by ---).
| x-------- |xx | | xx | | xxx | |.......xxx--------- | | xxxx | | | xxxx | | |.........xxxxx------------ | | | xxxxx | | | | xxxxxx | | | |..............xxxxxx---------------------- | | | | xxxxxxx | | | | | xxxxxxx | | | | | xxxxxxxx| +===========================================================================
The numbers are generated by generating a pair of numbers uniformly distributed over these rectangles and then accepting the X coordinate as the next random number if the pair corresponds to a point below the density function. The acceptance can be done in two stages, the first being whether the number is below the dotted line. This means that the density function need be checked only very occasionally and on the average only just over 3 uniform random numbers are required for each of the random numbers produced by this generator.
See PosGenX or Exponential for the method of deriving a class to generate random
numbers from a given distribution.
Note that the probability density p(x) must drop to exactly 0 for the argument, x, large enough. For example, include a statement in the program for p(x) that, if the value is less than 1.0E-15, then return 0. |
SymGen is a modification of PosGen for unimodal distributions symmetric about the origin, such as the standard normal.
A general random number generator for unimodal distributions following the method used by PosGen. The constructor takes one argument: the location of the mode of the distribution.
This is for generating random numbers taking just a finite number of values. There are two alternative forms of the constructor:
DiscreteGen D(n,prob); DiscreteGen D(n,prob,val);
where n is an integer giving the number of values, prob a Real array of length n giving the probabilities and val a Real array of length n giving the set of values that are generated. If val is omitted the values are 0,1,...,n-1.
The method requires two uniform random numbers for each number it produces. This method is described by Kronmal and Peterson, American Statistician, 1979, Vol 33, No 4, pp214-218.
This is for building a random number generator as a linear or multiplicative combination of existing random number generators. Suppose RV1, RV2, RV3, RV4 are random number generators defined with constructors given above and r1, r2, r0 are Reals and i1, i3 are integers.
Then the generator S defined by something like
SumRandom S = RV1(i1)*r1 - RV2*r2 + RV3(i3)*RV4 + r0;
has the obvious meaning. RV1(i1) means that the sum of i1 independent values from RV1 should be used. Note that RV1*RV1 means the product of two independent numbers generated from RV1. Remember that SumRandom is slow if the number of terms or copies is large. I support the four arithmetic operators +, -, * and / but cannot calculate the means and variances if you divide by a random variable.
Use SumRandom to quickly set up simple combinations of the existing generators. But if the combination is going to be used extensively, then it is probably better to write a new class to do this.
Example: normal with mean = 10, standard deviation = 5:
Normal N; SumRandom Z = 10 + 5 * N; for (int i=0; i<100; i++) cout << Z.Next() << "\n";
Example: F distribution with m and n degrees of freedom:
int m, n; ... put values in m and n ChiSq Num(m); ChiSq Den(n); SumRandom F = (double)n/(double)m * Num / Den; for (int i=0; i<100; i++) cout << F.Next() << "\n";
This is for mixtures of distributions. Suppose rv1, rv2, rv3 are random number generators and p1, p2, p3 are Reals summing to 1. Then the generator M defined by
MixedRandom M = rv1(p1) + rv2(p2) + rv3(p3);
produces a random number generator with selects its next random number from rv1 with probability p1, rv2 with probability p2, rv3 with probability p3.
Alternatively one can use the constructor
MixedRandom M(n, prob, rv);
where n is the number of distributions in the mixture, prob the Real array of probabilities, rv an array of pointers to random variables.
Normal with outliers:
Normal N; Cauchy C; MixedRandom Z = N(0.9) + C(0.1); for (int i=0; i<100; i++) cout << Z.Next() << "\n";
or:
Normal N; MixedRandom Z = N(0.9) + (10*N)(0.1); for (int i=0; i<100; i++) cout << Z.Next() << "\n";
To draw M numbers without replacement from start, start+1, ..., start+N-1 use
RandomPermutation RP; RP.Next(N, M, p, start);
where p is an int* pointing to an array of length M or longer. Results are returned to that array.
RP.Next(N, p, start);
assumes M = N. The parameter, start has a default value of 0.
The method is rather inefficient if N is very large and M is much smaller.
To draw M numbers without replacement from start, start+1, ..., start+N-1 and then sort use
RandomCombination RC; RC.Next(N, M, p, start);
where p is an int* pointing to an array of length M or longer. Results are returned to that array.
RC.Next(N, p, start);
assumes M = N. The parameter, start has a default value of 0.
The method is rather inefficient if N is large. A better approach for large N would be to generate the sorted combination directly. This would also provide a better way of doing permutations with large N, small M.
Use this class if you want to generate a Poisson random variable but you want to change the parameter frequently, so using the Poisson class would be inefficient. There are two member functions
int VariPoisson::iNext(Real mu); Real VariPoisson::Next(Real mu);
which return a new Poisson random number with mean mu. To generate 100 Poisson random numbers with means 1,2,...,100 use the following program
VariPoisson VP; for (int i = 1; i <= 100; ++i) { Real mu = i; cout << VP.iNext(mu) << end; }
The constructor is slow so put it outside any loop. The individual calls to iNext should be quite fast. The method is approximate for mu >= 300. The constructor is not in any class hierarchy and iNext is not virtual.
This class is somewhat beta-ish and may change in a future release of newran.
Use this class if you want to generate a Binomial random variable but you want to change the parameters of the frequently, so using the Binomial class would be inefficient. There are two member functions
int VariBinomial::iNext(int n, Real p); Real VariBinomial::Next(int n, Real p);
which returns a new Binomial random number with number of trials n and probability of success p. To generate 100 Binomial random numbers with n = 1,2,...,100 and p = 0.5 use the following program
VariBinomial VB; for (int n = 1; n <= 100; ++n) { Real p = 0.5; cout << VB.iNext(n, p) << end; }
The constructor is slow so put it outside any loop. The individual calls to iNext should be quite fast. The method is approximate if both n*p > 200 and n*(1-p) > 200. The constructor is not in any class hierarchy and iNext is not virtual.
This class is somewhat beta-ish and may change in a future release of newran.
Use this class if you want to generate a log normal random variable and you want to change the parameters of the frequently. There is one member function
Real VariLogNormal::Next(Real mean, Real sd);
which returns a new log normal random number with mean mean and standard deviation sd. Note that mean and sd are the mean and standard deviation of the log normal distribution and not of the underlying normal distribution. To generate 100 log normal random numbers with mean = 1,2,...,100 and sd = 1.0 use the following program
VariLogNormal VLN; for (int i = 1; i <= 100; ++i) { Real mean = i; Real sd = 1.0; cout << VLN.Next(mean, sd) << end; }
The constructor is not in any class hierarchy and Next is not virtual. This class is somewhat beta-ish and may change in a future release of newran.
A class consisting of a Real and an enumeration, EXT_REAL_CODE, taking the following values:
The arithmetic functions +, -, *, / are defined in the obvious ways, as is << for printing. The constructor can take either a Real or a value of EXT_REAL_CODE as an argument. If there is no argument the object is given the value Missing. Member function IsReal() returns true if the enumeration value is Finite and in this case value of the Real can be found with Value(). The enumeration value can be found with member function Code().
ExtReal is used at the type for values returned from the Mean and Variance member functions since these values may be infinite, indefinite or missing.
Non-central chi-squared with one degree of freedom. Used as part of ChiSq.
This generates random numbers from a gamma distribution with shape parameter alpha < 1. Because the density is infinite at x = 0 a power transform is required. The constructor takes alpha as an argument.
Gamma distribution for the shape parameter, alpha, greater than 1. The constructor takes alpha as the argument.
Poisson distribution; derived from AsymGen. The constructor takes the mean as the argument. Used by Poisson for values of the mean greater than 10.
Poisson distribution with mean less than or equal to 10. Uses DiscreteGen. Constructor takes the mean as its argument.
Binomial distribution; derived from AsymGen. Used by Binomial for n >= 40. Constructor takes n and p as arguments.
Binomial distribution with n < 40. Uses DiscreteGen. Constructor takes n and p as arguments.
These are used by SumRandom and MixedRandom.
Distribution type | Method | Example |
---|---|---|
Continuous finite unimodal density (no parameters, can calculate density) | Use PosGenX, SymGenX or AsymGenX. | |
Continuous finite unimodal density (with parameters, can calculate density) | Derive a new class from PosGen, SymGen or AsymGen, over-ride Density. | Gamma2 |
Can calculate inverse of distribution | Transform uniform random number. | Pareto |
Transformation of supported random number | Derive a new class from the existing class | ChiSq1 |
Transformation of several random numbers | Derive new class from Random; generate the new random number from the existing generators. | ChiSq |
Density with infinite singularity | Transform a random variable generated by PosGen, SymGen or AsymGen. | Gamma1 |
Distribution with several modes | Breakdown into a mixture of unimodal distributions. | |
Linear or quadratic combination of supported random numbers | Use SumRandom. | |
Mixture of supported random numbers | Use MixedRandom. | |
Discrete distribution (< 100 possible values) | Use DiscreteGen. | Poisson2 |
Discrete distribution (many possible values) | Use PosGen, SymGen or AsymGen. | Poisson1 |
The Shell sort and quick sort are adapted from Algorithms in C++ by Sedgewick published by Addison Wesley. The log gamma function coefficients were found using a modification of Paul Godfrey's matrix multiplication method - see http://home.att.net/~numericana/answer/info/godfrey.htm.
See also the section on the uniform generators.
readme.txt | readme file |
nr03doc.htm | this file |
rbd.css | style sheet for nr03doc.htm. |
newran.h | header file for newran |
newran1.cpp | body file for uniform random number generators |
newran2.cpp | body file for non-uniform distributions |
extreal.h | header file for extended reals |
extreal.cpp | body file for extended reals |
simpstr.h | header file for simple string class |
simpstr.cpp | body file for simple string class |
myexcept.h | header file for exceptions |
myexcept.cpp | body file for exceptions |
include.h | option file |
tryrand.h | header file for tryrand |
tryrand.cpp | test file |
tryrand1.cpp | called by tryrand - histograms of simple examples |
tryrand2.cpp | called by tryrand - histograms of advanced examples |
tryrand3.cpp | called by tryrand - statistical tests |
tryrand4.cpp | called by tryrand - test permutations |
tryrand5.cpp | called by tryrand - test "vari" versions of generators |
tryrand6.cpp | called by tryrand - test stable generators |
tryrand.txt | output from tryrand |
tryurng.h | header file for tryurng |
tryurng.cpp | test file for uniform random number generators |
tryurng1.cpp | called by tryurng |
test_out.h | header file for statistical test print out |
test_out.cpp | body file for statistical test print out |
utility.h | header file for statistical distributions calculation |
utility.cpp | body file for statistical distributions calculation |
format.h | header file for formatted printout |
format.cpp | body file for formatted printout |
str.h | header file for string class |
str.cpp | body file for string class |
array.h | simple array class |
tryurng.txt | output from tryurng |
geturng.cpp | get dataset from uniform random number generators |
nr_ex.cpp | example file |
nr_ex.txt | output from example file |
fm.txt | seed file for Fishman Moore generator |
lgm.txt | seed file for LGM generator |
lgm_mixed.txt | seed file for mixed LGM generator |
mother.txt | seed file for mother-of-all generator |
mt19937.txt | seed file for Mersenne twister generator |
multwc.txt | seed file for multiply with carry generator |
wh.txt | seed file for Wichmann Hill generator |
nr_cc.mak | make file for CC compiler |
nr_gnu.mak | make file for gnu G++ compiler |
nr_il8.mak | make file for Intel 8, 9 or 10 compilers under Linux |
nr_b55.mak | make file for Borland 5.5 compiler |
nr_b56.mak | make file for Borland 5.6 compiler |
nr_b58.mak | make file for Borland 5.8 compiler |
nr_m6.mak | make file for Microsoft Visual C++ 6, 7 and 7.1 |
nr_m8.mak | make file for Microsoft Visual C++ 8 |
nr_i8.mak | make file for Intel C++ 8 or 9 for MS Windows |
nr_i10.mak | make file for Intel C++ 10 for MS Windows |
nr_ow.mak | make file for Open Watcom compiler |
nr_targ.txt | list of targets for generating make file |
newran.lfl | list of library files for generating make file |
_newran.dox | description file about newran for doxygen |
_rbd_com.dox | description file about common files for doxygen |
The following diagram gives the class hierarchy of the package.
ExtReal.......................... Extended real numbers Random........................... Uniform random number generator | +---Constant.................... Return a constant | +---PosGen...................... Used by PosGenX etc | | | +---PosGenX................ Positive random #s from decreasing density | | | +---Exponential............ Negative exponential rng | | | +---Gamma1................. Used by Gamma (shape parameter < 1) | | | +---SymGen................. Used by SymGenX etc | | | +---SymGenX........... Random numbers from symmetric density | | | +---Cauchy............ Cauchy random number generator | | | +---Normal............ Standard normal random number generator | | | +---ChiSq1....... Used by ChiSq (one df) | +---AsymGen..................... Used by AsymGenX etc | | | +---AsymGenX............... Random numbers from asymmetric density | | | +---Poisson1............... Used by Poisson (mean > 8) | | | +---Binomial1.............. Used by Binomial (n >= 40) | | | +---NegativeBinomial....... Negative binomial random number generator | | | +---Gamma2................. Used by Gamma (shape parameter > 1) | +---Uniform..................... Uniform random number generator | +---ChiSq....................... Non-central chi-squared rng | +---Gamma....................... Gamma random number generator | +---Pareto...................... Pareto random number generator | +---DiscreteGen................. Discrete random number generator | +---Poisson2.................... Used by Poisson (mean <= 8) | +---Binomial2................... Used by Binomial (n < 40) | +---Poisson..................... Poisson random number generator | +---Binomial.................... Binomial random number generator | +---Stable...................... Stable random number generator | +---SumRandom................... Sum of random numbers | +---MixedRandom................. Mixture of random numbers | +---MultipliedRandom............ Used by SumRandom | | | +---AddedRandom............ Used by SumRandom | | | +---SubtractedRandom....... Used by SumRandom | +---ShiftedRandom............... Used by SumRandom | | | +---ReverseShiftedRandom... Used by SumRandom | | | +---ScaledRandom........... Used by SumRandom | +---NegatedRandom.......... .... Used by SumRandom | +---RepeatedRandom.............. Used by SumRandom | +---AddedSelectedRandom......... Used by MixedRandom | +---SelectedRandom.............. Used by MixedRandom | +---LGM_base.................... Base for two LGM generators | | | +---LGM_simple............. Ordinary LGM generator | | | +---LGM_mixed.............. Mixed LGM generator | +---WH.......................... Wichmann-Hill generator | +---FM.......................... Fishman-Moore generator | +---MotherOfAll................. Mother of all generator | +---MultWithCarry............... Multiply with carry generator | +---MT.......................... Mersenne twister generator | +---DummyRNG.................... Dummy generator RandomPermutation................ Random permutation | +---RandomCombination........... Sorted random permutation VariPoisson...................... Poisson generator VariBinomial..................... Binomial generator VariLogNormal.................... Log normal generator
July, 2008 - fix for 64 bits
April, 2006 - make compatible with G++ 4.1
September, 2005 - minor improvements, fix problem with Mother initialisation, start setting up comment structure for Doxygen
April, 2004 - better tests of permutation function, new log gamma function
November, 2003 - minor improvements
March, 2003 - include stable distribution generator
October, 2002 - new uniform RNGs
July, 2002 - bring into line with my other libraries; VariPoisson, VariBinomial, VariLogNormal classes; change to Sedgewick's Shell sort.
August, 1998 - update exception package; work around problem with MS VC++ 5
January, 1998 - version compatible with newmat09
1995 - newran version, additional distributions
1989 - initial version