/* Integer and floating point random number generator routines */ /* * Copyright 2000 Graeme W. Gill * All rights reserved. * * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- * see the License.txt file for licencing details. */ #include "numsup.h" #include "rand.h" /* 32 bit pseudo random sequencer based on XOR feedback */ /* generates number between 1 and 4294967295 */ #define PSRAND32(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1)) /* 32 bit linear congruent generator */ /* generates number between 0 and 4294967295 */ /* (From Knuth & H.W.Lewis) */ #define PSRAND32L(S) ((S) * 1664525L + 1013904223L) /* - - - - - - - - - - - - - - - */ /* Global state random generator */ static rand_state g_rand = { 0 }; /* Use default seed for global state generator */ /* Return a 32 bit number between 0 and 4294967295 */ /* Use Knuth shuffle to improve PSRAND32 sequence */ unsigned int rand32( /* Return 32 bit random number */ unsigned int seed /* Optional seed. Non-zero re-initialized with that seed */ ) { return rand32_th(NULL, seed); } /* return a random number between 0.0 and 1.0 */ /* based on rand32 */ double ranno(void) { return rand32_th(NULL, 0) / 4294967295.0; } /* Return a uniform random double in the range min to max */ double d_rand(double min, double max) { return d_rand_th(NULL, min, max); } /* Return a squared distribution random double in the range min to max */ double d2_rand(double min, double max) { return d2_rand_th(NULL, min, max); } /* Return a random integer in the range min to max inclusive */ int i_rand(int min, int max) { return i_rand_th(NULL, min, max); } /* Return a random floating point number with a gausian/normal */ /* distribution, centered about 0.0, with standard deviation 1.0 */ /* This uses the Box-Muller transformation */ double norm_rand(void) { return norm_rand_th(NULL); } /* - - - - - - - - - - - - - - - */ /* Explicit state random generator */ /* Init rand_state to default */ void rand_init(rand_state *p) { if (p == NULL) p = &g_rand; p->pvs_inited = 0; p->ran = 0; } /* Return a 32 bit number between 0 and 4294967295 */ /* Use Knuth shuffle to improve PSRAND32 sequence */ unsigned int rand32_th(rand_state *p, unsigned int seed /* Optional seed. Non-zero re-initialized with that seed */ ) { int i; if (p == NULL) p = &g_rand; if (seed != 0) { //printf("~1 rand 0x%x seed 0x%x\n",p,seed); p->pvs_inited = 0; p->ran = seed; } /* Init random storage locations */ if (p->pvs_inited == 0) { if (p->ran == 0) p->ran = RAND_SEED; for (i = 0; i < RAND_TSIZE; i++) p->pvs[i] = p->ran = PSRAND32(p->ran); p->last = p->ran; p->pvs_inited = 1; } i = p->last % RAND_TSIZE; /* New location */ p->last = p->pvs[i]; /* Value generated */ p->pvs[i] = p->ran = PSRAND32(p->ran); /* New value */ //printf("~1 rand 0x%x ret 0x%x\n",p,p->last-1); return p->last-1; } /* return a random number between 0.0 and 1.0 */ /* based on rand32 */ double ranno_th(rand_state *p) { return rand32_th(p, 0) / 4294967295.0; } /* Return a uniform random double in the range min to max */ double d_rand_th(rand_state *p, double min, double max) { return min + (max - min) * ranno_th(p); } /* Return a squared distribution random double in the range min to max */ double d2_rand_th(rand_state *p, double min, double max) { double val = ranno_th(p); return min + (max - min) * val * val; } /* Return a random integer in the range min to max inclusive */ int i_rand_th(rand_state *p, int min, int max) { return min + (int)floor(0.5 + ((double)(max - min)) * ranno_th(p)); } /* Return a random floating point number with a gausian/normal */ /* distribution, centered about 0.0, with standard deviation 1.0 */ /* This uses the Box-Muller transformation */ double norm_rand_th(rand_state *p) { if (p == NULL) p = &g_rand; if (p->r2 == 0) { double v1, v2, t1, t2, r1; do { v1 = d_rand_th(p, -1.0, 1.0); v2 = d_rand_th(p, -1.0, 1.0); t1 = v1 * v1 + v2 * v2; } while (t1 == 0.0 || t1 >= 1.0); t2 = sqrt(-2.0 * log(t1)/t1); p->nr2 = v2 * t2; /* One for next time */ p->r2 = 1; r1 = v1 * t2; return r1; } else { p->r2 = 0; return p->nr2; } }