2008-11-29 21:40:37 +01:00
|
|
|
|
/**********
|
|
|
|
|
|
Copyright 2008 Holger Vogt
|
|
|
|
|
|
**********/
|
|
|
|
|
|
/* Care about random numbers
|
|
|
|
|
|
The seed value is set as random number in main.c, line 746.
|
|
|
|
|
|
A fixed seed value may be set by 'set rndseed=value'.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2010-08-28 20:13:08 +02:00
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
CombLCGTaus()
|
|
|
|
|
|
Combined Tausworthe & LCG random number generator
|
|
|
|
|
|
Algorithm has been suggested in:
|
|
|
|
|
|
GPUGems 3, Addison Wesley, 2008, Chapter 37.
|
|
|
|
|
|
It combines a three component Tausworthe generator taus88
|
2012-10-20 21:27:15 +02:00
|
|
|
|
(see P. L’Ecuyer: "Maximally equidistributed combined Tausworthe
|
2010-08-28 20:13:08 +02:00
|
|
|
|
generators", Mathematics of Computation, 1996,
|
2012-10-20 21:27:15 +02:00
|
|
|
|
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps )
|
2010-08-28 20:13:08 +02:00
|
|
|
|
and a quick linear congruent generator (LCG), decribed in:
|
|
|
|
|
|
Press: "Numerical recipes in C", Cambridge, 1992, p. 284.
|
|
|
|
|
|
Generator has passed the bbattery_SmallCrush(gen) test of the
|
2012-10-20 21:27:15 +02:00
|
|
|
|
TestU01 library from Pierre L’Ecuyer and Richard Simard,
|
2010-08-28 20:13:08 +02:00
|
|
|
|
http://www.iro.umontreal.ca/~simardr/testu01/tu01.html
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* TausSeed creates three start values for Tausworthe state variables.
|
|
|
|
|
|
Uses rand() from <stdlib.h>, therefore values depend on the value of
|
|
|
|
|
|
seed in srand(seed). A constant seed will result in a reproducible
|
|
|
|
|
|
series of random variates.
|
|
|
|
|
|
|
|
|
|
|
|
Calling sequence:
|
|
|
|
|
|
srand(seed);
|
|
|
|
|
|
TausSeed();
|
|
|
|
|
|
double randvar = CombLCGTaus(void);
|
|
|
|
|
|
*/
|
2010-08-28 23:06:42 +02:00
|
|
|
|
//#define HVDEBUG
|
2010-08-28 20:13:08 +02:00
|
|
|
|
|
2011-12-11 19:05:00 +01:00
|
|
|
|
#include "ngspice/ngspice.h"
|
|
|
|
|
|
#include "ngspice/cpdefs.h"
|
|
|
|
|
|
#include "ngspice/ftedefs.h"
|
2010-08-28 20:13:08 +02:00
|
|
|
|
#include <math.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
|
|
#include <process.h>
|
|
|
|
|
|
#else
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
#endif
|
|
|
|
|
|
#include <sys/timeb.h>
|
|
|
|
|
|
#include <stdarg.h> // var. argumente
|
|
|
|
|
|
|
|
|
|
|
|
/* Tausworthe state variables for double variates*/
|
|
|
|
|
|
static unsigned CombState1 = 129, CombState2 = 130, CombState3 = 131;
|
2010-09-01 23:13:01 +02:00
|
|
|
|
static unsigned CombState4 = 132; /* LCG state variable */
|
2010-08-28 20:13:08 +02:00
|
|
|
|
|
2010-09-01 23:13:01 +02:00
|
|
|
|
/* Tausworthe state variables for integer variates*/
|
2010-08-28 20:13:08 +02:00
|
|
|
|
static unsigned CombState5 = 133, CombState6 = 135, CombState7 = 137;
|
2010-09-01 23:13:01 +02:00
|
|
|
|
static unsigned CombState8 = 138; /* LCG state variable */
|
2010-08-28 20:13:08 +02:00
|
|
|
|
|
2010-09-01 23:13:01 +02:00
|
|
|
|
static unsigned TauS(unsigned *state, int C1, int C2, int C3, unsigned m);
|
|
|
|
|
|
static unsigned LGCS(unsigned *state, unsigned A1, unsigned A2);
|
2008-11-29 21:40:37 +01:00
|
|
|
|
|
2010-09-01 23:13:01 +02:00
|
|
|
|
double CombLCGTaus(void);
|
2010-10-08 20:05:00 +02:00
|
|
|
|
float CombLCGTaus2(void);
|
2010-09-01 23:13:01 +02:00
|
|
|
|
unsigned int CombLCGTausInt(void);
|
2010-10-08 20:05:00 +02:00
|
|
|
|
unsigned int CombLCGTausInt2(void);
|
2010-12-19 12:05:03 +01:00
|
|
|
|
double exprand(double);
|
2008-11-29 21:40:37 +01:00
|
|
|
|
|
|
|
|
|
|
void checkseed(void);
|
|
|
|
|
|
double drand(void);
|
2010-12-28 20:01:30 +01:00
|
|
|
|
double gauss0(void);
|
2010-12-30 15:49:35 +01:00
|
|
|
|
void rgauss(double* py1, double* py2);
|
2010-12-28 20:01:30 +01:00
|
|
|
|
int poisson(double);
|
2008-11-29 21:40:37 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check if a seed has been set by the command 'set rndseed=value'
|
|
|
|
|
|
in spinit with integer value > 0. If available, call srand(value).
|
|
|
|
|
|
This will override the call to srand in main.c.
|
2010-09-02 18:14:34 +02:00
|
|
|
|
Checkseed should be put in front of any call to rand or CombLCGTaus.. .
|
2008-11-29 21:40:37 +01:00
|
|
|
|
*/
|
2010-06-23 20:57:13 +02:00
|
|
|
|
void checkseed(void)
|
2008-11-29 21:40:37 +01:00
|
|
|
|
{
|
|
|
|
|
|
int newseed;
|
|
|
|
|
|
static int oldseed;
|
|
|
|
|
|
/* printf("Enter checkseed()\n"); */
|
2010-07-17 22:48:20 +02:00
|
|
|
|
if (cp_getvar("rndseed", CP_NUM, &newseed)) {
|
2008-11-29 21:40:37 +01:00
|
|
|
|
if ((newseed > 0) && (oldseed != newseed)) {
|
2012-10-26 18:04:44 +02:00
|
|
|
|
srand((unsigned int)newseed);
|
2010-08-28 20:13:08 +02:00
|
|
|
|
TausSeed();
|
2008-11-29 21:40:37 +01:00
|
|
|
|
oldseed = newseed;
|
|
|
|
|
|
printf("Seed value for random number generator is set to %d\n", newseed);
|
|
|
|
|
|
}
|
|
|
|
|
|
/* else printf("Oldseed %d, newseed %d\n", oldseed, newseed); */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-09-02 18:14:34 +02:00
|
|
|
|
/* uniform random number generator, interval [-1 .. +1[ */
|
2010-06-23 20:57:13 +02:00
|
|
|
|
double drand(void)
|
2008-11-29 21:40:37 +01:00
|
|
|
|
{
|
|
|
|
|
|
checkseed();
|
2010-09-01 23:13:01 +02:00
|
|
|
|
// return ( 2.0*((double) (RR_MAX-abs(rand())) / (double)RR_MAX-0.5));
|
|
|
|
|
|
return 2.0 * CombLCGTaus() - 1.0;
|
2008-11-29 21:40:37 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-28 20:13:08 +02:00
|
|
|
|
void TausSeed(void)
|
|
|
|
|
|
{
|
2010-09-01 23:13:01 +02:00
|
|
|
|
/* The Tausworthe initial states should be greater than 128.
|
2010-09-02 18:14:34 +02:00
|
|
|
|
We restrict the values up to 32767.
|
|
|
|
|
|
Here we use the standard random functions srand, called in main.c
|
|
|
|
|
|
upon ngspice startup or later in fcn checkseed(),
|
|
|
|
|
|
rand() and the maximum return value RAND_MAX*/
|
|
|
|
|
|
CombState1 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
|
|
|
|
|
CombState2 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
|
|
|
|
|
CombState3 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
|
|
|
|
|
CombState4 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
|
|
|
|
|
CombState5 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
|
|
|
|
|
CombState6 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
|
|
|
|
|
CombState7 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
|
|
|
|
|
CombState8 = (unsigned int)((double)rand()/(double)RAND_MAX * 32638.) + 129;
|
2010-09-01 23:13:01 +02:00
|
|
|
|
|
2010-08-28 20:13:08 +02:00
|
|
|
|
#ifdef HVDEBUG
|
|
|
|
|
|
printf("\nTausworthe Double generator init states: %d, %d, %d, %d\n",
|
|
|
|
|
|
CombState1, CombState2, CombState3, CombState4);
|
|
|
|
|
|
printf("Tausworthe Integer generator init states: %d, %d, %d, %d\n",
|
|
|
|
|
|
CombState5, CombState6, CombState7, CombState8);
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-09-01 23:13:01 +02:00
|
|
|
|
static unsigned TauS(unsigned *state, int C1, int C2, int C3, unsigned m)
|
2010-08-28 20:13:08 +02:00
|
|
|
|
{
|
|
|
|
|
|
unsigned b = (((*state << C1) ^ *state) >> C2);
|
|
|
|
|
|
return *state = (((*state & m) << C3) ^ b);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-09-01 23:13:01 +02:00
|
|
|
|
static unsigned LGCS(unsigned *state, unsigned A1, unsigned A2)
|
2010-08-28 20:13:08 +02:00
|
|
|
|
{
|
|
|
|
|
|
return *state = (A1 * *state + A2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-09-02 18:14:34 +02:00
|
|
|
|
/* generate random variates randvar uniformly distributed in
|
|
|
|
|
|
[0.0 .. 1.0[ by calls to CombLCGTaus() like:
|
|
|
|
|
|
double randvar = CombLCGTaus();
|
|
|
|
|
|
*/
|
2010-09-07 22:11:13 +02:00
|
|
|
|
double CombLCGTaus(void)
|
2010-08-28 20:13:08 +02:00
|
|
|
|
{
|
|
|
|
|
|
return 2.3283064365387e-10 * (
|
|
|
|
|
|
TauS(&CombState1, 13, 19, 12, 4294967294UL) ^
|
|
|
|
|
|
TauS(&CombState2, 2, 25, 4, 4294967288UL) ^
|
|
|
|
|
|
TauS(&CombState3, 3, 11, 17, 4294967280UL) ^
|
|
|
|
|
|
LGCS(&CombState4, 1664525, 1013904223UL)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2010-09-02 18:14:34 +02:00
|
|
|
|
|
|
|
|
|
|
/* generate random variates randvarint uniformly distributed in
|
|
|
|
|
|
[0 .. 4294967296[ (32 bit unsigned int) by calls to CombLCGTausInt() like:
|
|
|
|
|
|
unsigned int randvarint = CombLCGTausInt();
|
|
|
|
|
|
*/
|
2010-09-07 22:11:13 +02:00
|
|
|
|
unsigned int CombLCGTausInt(void)
|
2010-08-28 20:13:08 +02:00
|
|
|
|
{
|
|
|
|
|
|
return (
|
|
|
|
|
|
TauS(&CombState5, 13, 19, 12, 4294967294UL) ^
|
|
|
|
|
|
TauS(&CombState6, 2, 25, 4, 4294967288UL) ^
|
|
|
|
|
|
TauS(&CombState7, 3, 11, 17, 4294967280UL) ^
|
|
|
|
|
|
LGCS(&CombState8, 1664525, 1013904223UL)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-09-02 18:14:34 +02:00
|
|
|
|
/* test versions of the generators listed above */
|
2010-09-07 22:11:13 +02:00
|
|
|
|
float CombLCGTaus2(void)
|
2010-08-28 20:13:08 +02:00
|
|
|
|
{
|
|
|
|
|
|
unsigned long b;
|
|
|
|
|
|
b = (((CombState1 << 13) ^ CombState1) >> 19);
|
2012-10-26 18:04:44 +02:00
|
|
|
|
CombState1 = (unsigned int)(((CombState1 & 4294967294UL) << 12) ^ b);
|
2010-08-28 20:13:08 +02:00
|
|
|
|
b = (((CombState2 << 2) ^ CombState2) >> 25);
|
2012-10-26 18:04:44 +02:00
|
|
|
|
CombState2 = (unsigned int)(((CombState2 & 4294967288UL) << 4) ^ b);
|
2010-08-28 20:13:08 +02:00
|
|
|
|
b = (((CombState3 << 3) ^ CombState3) >> 11);
|
2012-10-26 18:04:44 +02:00
|
|
|
|
CombState3 = (unsigned int)(((CombState3 & 4294967280UL) << 17) ^ b);
|
|
|
|
|
|
CombState4 = (unsigned int)(1664525 * CombState4 + 1013904223UL);
|
|
|
|
|
|
return ((float)(CombState1 ^ CombState2 ^ CombState3 ^ CombState4) * 2.3283064365387e-10f);
|
2010-08-28 20:13:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-09-07 22:11:13 +02:00
|
|
|
|
unsigned int CombLCGTausInt2(void)
|
2010-08-28 20:13:08 +02:00
|
|
|
|
{
|
|
|
|
|
|
unsigned long b;
|
|
|
|
|
|
b = (((CombState5 << 13) ^ CombState5) >> 19);
|
2012-10-26 18:04:44 +02:00
|
|
|
|
CombState5 = (unsigned int)(((CombState5 & 4294967294UL) << 12) ^ b);
|
2010-08-28 20:13:08 +02:00
|
|
|
|
b = (((CombState6 << 2) ^ CombState6) >> 25);
|
2012-10-26 18:04:44 +02:00
|
|
|
|
CombState6 = (unsigned int)(((CombState6 & 4294967288UL) << 4) ^ b);
|
2010-08-28 20:13:08 +02:00
|
|
|
|
b = (((CombState7 << 3) ^ CombState7) >> 11);
|
2012-10-26 18:04:44 +02:00
|
|
|
|
CombState7 = (unsigned int)(((CombState7 & 4294967280UL) << 17) ^ b);
|
|
|
|
|
|
CombState8 = (unsigned int)(1664525 * CombState8 + 1013904223UL);
|
2010-08-28 20:13:08 +02:00
|
|
|
|
return (CombState5 ^ CombState6 ^ CombState7 ^ CombState8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-11-29 21:40:37 +01:00
|
|
|
|
/*** gauss ***/
|
|
|
|
|
|
|
2010-12-28 20:01:30 +01:00
|
|
|
|
double gauss0(void)
|
2008-11-29 21:40:37 +01:00
|
|
|
|
{
|
|
|
|
|
|
static bool gliset = TRUE;
|
|
|
|
|
|
static double glgset = 0.0;
|
|
|
|
|
|
double fac,r,v1,v2;
|
|
|
|
|
|
if (gliset) {
|
|
|
|
|
|
do {
|
2010-08-28 23:06:42 +02:00
|
|
|
|
v1 = drand(); v2 = drand();
|
2008-11-29 21:40:37 +01:00
|
|
|
|
r = v1*v1 + v2*v2;
|
|
|
|
|
|
} while (r >= 1.0);
|
|
|
|
|
|
/* printf("v1 %f, v2 %f\n", v1, v2); */
|
|
|
|
|
|
fac = sqrt(-2.0 * log(r) / r);
|
|
|
|
|
|
glgset = v1 * fac;
|
|
|
|
|
|
gliset = FALSE;
|
|
|
|
|
|
return v2 * fac;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
gliset = TRUE;
|
|
|
|
|
|
return glgset;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-11-27 17:36:03 +01:00
|
|
|
|
|
|
|
|
|
|
/* Polar form of the Box-Muller generator for Gaussian distributed
|
|
|
|
|
|
random variates.
|
|
|
|
|
|
Generator will be fed with two uniformly distributed random variates.
|
|
|
|
|
|
Delivers two values per call
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void rgauss(double* py1, double* py2)
|
|
|
|
|
|
{
|
|
|
|
|
|
double x1, x2, w;
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
x1 = 2.0 * CombLCGTaus() - 1.0;
|
|
|
|
|
|
x2 = 2.0 * CombLCGTaus() - 1.0;
|
|
|
|
|
|
w = x1 * x1 + x2 * x2;
|
|
|
|
|
|
} while ( w >= 1.0 );
|
|
|
|
|
|
|
|
|
|
|
|
w = sqrt( (-2.0 * log( w ) ) / w );
|
|
|
|
|
|
|
|
|
|
|
|
*py1 = x1 * w;
|
|
|
|
|
|
*py2 = x2 * w;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-28 20:01:30 +01:00
|
|
|
|
|
|
|
|
|
|
/** Code by: Inexpensive
|
|
|
|
|
|
http://everything2.com/title/Generating+random+numbers+with+a+Poisson+distribution **/
|
|
|
|
|
|
int poisson(double lambda)
|
|
|
|
|
|
{
|
|
|
|
|
|
int k=0; //Counter
|
|
|
|
|
|
const int max_k = 1000; //k upper limit
|
|
|
|
|
|
double p = CombLCGTaus(); //uniform random number
|
|
|
|
|
|
double P = exp(-lambda); //probability
|
|
|
|
|
|
double sum=P; //cumulant
|
|
|
|
|
|
if (sum>=p) return 0; //done allready
|
|
|
|
|
|
for (k=1; k<max_k; ++k) { //Loop over all k:s
|
|
|
|
|
|
P*=lambda/(double)k; //Calc next prob
|
|
|
|
|
|
sum+=P; //Increase cumulant
|
|
|
|
|
|
if (sum>=p) break; //Leave loop
|
|
|
|
|
|
}
|
|
|
|
|
|
return k; //return random number
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-19 12:05:03 +01:00
|
|
|
|
/* return an exponentially distributed random number */
|
|
|
|
|
|
double exprand(double mean)
|
|
|
|
|
|
{
|
|
|
|
|
|
double expval;
|
|
|
|
|
|
checkseed();
|
|
|
|
|
|
expval = -log(CombLCGTaus()) * mean;
|
|
|
|
|
|
return expval;
|
|
|
|
|
|
}
|