Tina's Random Number Generators (TRNG) is a C++ parallel pseudo random number generators package.
A lot of tasks in scientific computing can only be tackled by the power of parallel computers. Especially Monte Carlo simmulations are often well suited for parallel computers because of the inherent parallelism of these problems.
A straight forward way to generate pseudo random numbers in a parallel environment is to use the same serial pseudo random number generator on every processor but with (randomly chosen) different seeds or the same generator type but with different parameter sets. These methods are quiet arbitrary and it is not possible to enshure in every case that there are no correlations between the pseudo random number sequences.
To create a good pseudo random number generator for parallel applications we take an excellent sequential pseudo random number generator and distribute its numbers in a well defined way over the parallel jobs. There are two different approaches in distributing the numbers.
For a performand implementation it is necessary that
can be easy calculated from
even for large
.
![]() |
![]() |
A way to implement the leapfrog method could be to dedicate one processor to random number generation and spread these numbers via a network to the other processors. But this wold be a very inefficient way.
TRNG (Tina's Random Number Generators) is a library that gives you a powerfull tool for Monte Carlo simmulations on parallel computers. TRNG is a collection of random number generators specially designed for the needs of parallel Monte Carlo simmulations. With TRNG you can generate parallel streams of pseudo random numbers (with leapfrog or sequence splitting method) without any communication. Tina's Random Number Generators have a highly tuned implementation, have a long period and are empirically tested. Tina's Random Number Generators are easy to use and can be extendend by the user. It is a tool for your everyday work.
Software Distribution and Instalation
Tina's Random Number Generators are copyrighted by Heiko Bauke. You can contact TRNG's author via electronic mail to heiko.bauke@student.uni-magdeburg.de
and get the software from http://tina.nat.uni-magdeburg.de/TRNG
.
TRNG is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. See the GNU General Public License for more details.
Download the latest tar file from http://tina.nat.uni-magdeburg.de/TRNG
and unpack and untar the file with gzip -c -d trng-2.0.0.tar.gz | tar -xvf -
. Change into the directory trng-2.0.0
and type make
. After you have become root type make install
. That's all!
If you don't have the GNU compiler but the SUN-Workshop compiler use the makefile Makefile.SW
and type make -f Makefile.SW
and make -f Makefile.SW install
.
If you have installed TRNG successfully you can compile programs that use Tina's Random Number Generators, just include the header file trng.h
and use the linker flag -ltrng
.
TRNG comes with some example- and test-programs. You may compile these programs with make examples
(or make -f Makefile.SW examples
). The binaries are located in the directory bin
. To compile the MPI-examples you need a MPI-Implementation with C++-support like LAM (http://www.lam-mpi.org
). Start these programs without commandline arguments to get a short description. The reader should investigate the following programs.
plausibility
This program does some tests for leapfrog and sequence splitting. diehard_file
With this program you can generate files for applying the diehard test . pi
This MPI program shows how to use TRNG. It computes pi_advanced
This is a version of the program pi where the result is independent of the number processors. exception
This is an example for exception handling in TRNG. template_demo
TRNG is implemeted by using templates. This example shows how hande these templates. copy_demo
is a demo programm that shows the difference between random number assigment and the copy function.heiko.bauke@student.uni-magdeburg.de
.
In the following program we compute
by a Monte Carlo simmulation. The program uses MPI.
// ************************************************************* // // Monte-Carlo-pi-Calulation // // ************************************************************* #include <cstdlib> #include <cmath> #include <iostream> #include <trng.h> #include <mpi++.h> using namespace TRNG; using namespace std; int main(int argc, char *argv[]) { // number of points in quare const long all_samples=1000000l; // pseudo random number generator object LCG64 r; // MPI initialisation MPI::Init(argc, argv); // get rank and number of processes int size=MPI::COMM_WORLD.Get_size(); int rank=MPI::COMM_WORLD.Get_rank(); // split sequence of pseudo random numbers by leapfrog method r.split(size, rank); // no points in the quare long in=0l; // compute number of points per processor long num_samples=all_samples/size; // all_samples is not a multiple of size if (all_samples%size>rank) ++num_samples; for (long i=0l; i<num_samples; ++i) { double x=r.uniform(); double y=r.uniform(); // is point in square if (x*x+y*y<=1.0) // yes? increment in ++in; } // collect results and print pi long in_all; MPI::COMM_WORLD.Reduce(&in, &in_all, 1, MPI::LONG, MPI::SUM, 0); if (rank==0) { double pi=4.0*static_cast<double>(in_all)/static_cast<double>(all_samples); cout << "pi = " << pi << endl; } // quit MPI MPI::Finalize(); return EXIT_SUCCESS; }
The first version of our program gives not rusults independent of number of processors. The second version shows how to make the program independent of the number of used processors. The trick is to use different generators to calculate the
- and
-coordinates.
// ************************************************************* // // Monte-Carlo-pi-Calulation // // ************************************************************* #include <cstdlib> #include <cmath> #include <iostream> #include <trng.h> #include <mpi++.h> using namespace TRNG; using namespace std; int main(int argc, char *argv[]) { // number of points in quare const long all_samples=1000000l; // pseudo random number generator object LCG64 rx; LCG64 ry; // jump 2^26 steps ahead; 2^26 >> all_samples ry.jump2(26); // MPI initialisation MPI::Init(argc, argv); // get rank and number of processes int size=MPI::COMM_WORLD.Get_size(); int rank=MPI::COMM_WORLD.Get_rank(); // split sequence of pseudo random numbers by leapfrog method rx.split(size, rank); ry.split(size, rank); // no points in the quare long in=0l; // compute number of points per processor long num_samples=all_samples/size; // all_samples is not a multiple of size if (all_samples%size>rank) ++num_samples; for (long i=0l; i<num_samples; ++i) { double x=rx.uniform(); double y=ry.uniform(); // is point in square if (x*x+y*y<=1.0) // yes? increment in ++in; } // collect results and print pi long in_all; MPI::COMM_WORLD.Reduce(&in, &in_all, 1, MPI::LONG, MPI::SUM, 0); if (rank==0) { double pi=4.0*static_cast<double>(in_all)/static_cast<double>(all_samples); cout << "pi = " << pi << endl; } // quit MPI MPI::Finalize(); return EXIT_SUCCESS; }
If a TRNG function is called with an invalid argument this function throws an exception TRNG::error. The next example shows how to handle these exceptions.
#include <cstdlib> #include <iostream> #include <trng.h> using namespace std; using namespace TRNG; int main(void) { ParkMiller R; cout << R.normal_dist() << endl; try { R.jump2(16l); cout << "jumped forward" << endl; // you can't jump backwards R.jump2(-16l); cout << "jumped backward" << endl; } catch (error e) { cerr << "oops!! " << e.message << endl; } catch (...) { cerr << "something else went wrong" << endl; } return EXIT_SUCCESS; }
Sometimes it is desired to use a random number generator object as a function argument. Tina's random number genrators are implemented by a template technique. The next program is an example with a function with a random number generator as an argument.
#include <cstdlib> #include <iostream> #include <trng.h> using namespace std; using namespace TRNG; template<class RNG_type> void foo(RNG_type &R) { cout << R.rand() << " is a random number from generator " << R.name() << endl; } int main(void) { ParkMiller R1; LCG64 R2; foo(R1); foo(R2); return EXIT_SUCCESS; }
Youd cant find your favourite Tina's Random Number Generators? No problem! Yust extend TRNG to your needs. In the following example we implement an exclusive or lagged fibonacci generator. This example shows only how TRNG could be extented in principle. Sequence splitting and leapfrog method are implemented in a very stupid way. Unused values are just thrown away. Don't uses this generator in your applications. Doun't use exclusive or lagged fibonacci generator at all.
// --------------------------------------------------------------------- // Time-stamp: <Freitag, 04.01.2002, 0:34:15; edited by heiko> // // Tina's random number generators TRNG // // lagged Fibonacci generator // // Copyright (C) 2001, 2002 Heiko Bauke // // heiko.bauke@student.uni-magdeburg.de // // TRNG is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation. This program // is distributed WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // --------------------------------------------------------------------- #ifndef FIBONACCI_H #define FIBONACCI_H #include <iostream> #include <strstream> #include <new> #include <trng.h> // This is an example for extending Tina's random number generators. // We implement a exclusive or lagged Fibonacci generator. // // r_i=r_(i-q) xor r_(i-p); p>q // // Sequence splitting and leapfrog method are implemented in a very stupid // way. Unused values are just thrown away. Don't uses this generator in // your applications. // the template parametr determine the lags template<long p1, long q1> class Fibonacci : public TRNG::RNG<Fibonacci<p1, q1> > { private: std::vector<long> r; long p, q, pointer, steps; TRNG::ParkMiller R_init; void backward(void) { for (long i=0l; i<steps; ++i) { r[pointer]=r[pointer]^r[(pointer+q)%p]; pointer=(pointer-1l+p)%p; } } public: // TRNG::user1_t for a user implemeneted rng static const TRNG::RNG_type type=TRNG::user1_t; const char * name(void) { return "Fibonacci"; } void reset(void) { steps=1l; max_val=0x7fffffffl; max_val2=max_val/2l; } // set the seed table using the generator TRNG::ParkMiller void seed(long s) { long h1, h2; h1=0x7fffffffl; h2=0x40000000l; R_init.seed(s); for (long i=0l; i<p; ++i) { if (i<q) { r[i]=((R_init.rand()+1l) & h1) | h2; h1>>=1; h2>>=1; if (h2==0) { h1=0x7fffffffl; h2=0x40000000l; } } else r[i]=0l; for (long j=0l; j<31l; ++j) { r[i]<<=1l; if (R_init.boolean()) ++r[i]; } } pointer=p-1l; } // calculate the next random number long rand(void) { for (long i=0l; i<steps; ++i) { ++pointer; if (pointer==p) pointer=0l; r[pointer]=r[pointer]^r[(pointer+q)<p ? (pointer+q) : (pointer+q-p)]; } return(r[pointer]); } void split(long s, long n) { if (s<1l || n>s || n<0l) throw TRNG::error("invalid arguments for Fibonacci::split"); if (s>1l) { for (long i=0l; i<=n; ++i) rand(); steps*=s; backward(); } } void jump2(long s) { if (s<0l) throw TRNG::error("invalid argument for Fibonacci::split"); unsigned long long to=1ull<<s; for (unsigned long long i=0ull; i<to; ++i) { rand(); } } void save_status(std::vector<long> &s) { s.resize(p+5); s[0]=type; s[1]=q; s[2]=p; s[3]=pointer; s[4]=steps; for (int i=0; i<p; ++i) s[i+5]=r[i]; } void load_status(const std::vector<long> &s) { if (s[0]!=type) throw TRNG::error("Fibonacci::load_status wrong parameter"); q=s[1]; p=s[2]; pointer=s[3]; steps=s[4]; r.resize(p); for (int i=0; i<p; ++i) r[i]=s[i+5]; } Fibonacci(long seed_=0l) : r() { if (p1<0l || q1<0l || p1==q1) throw TRNG::error("bad arguments for Fibonacci::Fibonacci"); if (p1>q1) { p=p1; q=q1; } else { p=q1; q=p1; } r.resize(p); reset(); seed(seed_); } virtual ~Fibonacci() {}; }; #endif