annotate RngStream.c @ 3:974d7be8eec4 tip

Update to pack-based dcg utilities
author samer
date Tue, 03 Oct 2017 11:52:23 +0100
parents b31415b4a196
children
rev   line source
samer@0 1 /***********************************************************************\
samer@0 2 *
samer@0 3 * File: RngStream.c for multiple streams of Random Numbers
samer@0 4 * Language: ANSI C
samer@0 5 * Copyright: Pierre L'Ecuyer, University of Montreal
samer@0 6 * Date: 14 August 2001
samer@0 7 * License: GPL version 2 or later
samer@0 8 *
samer@0 9 * Notice: Please contact P. L'Ecuyer at <lecuyer@iro.UMontreal.ca>
samer@0 10 * for commercial purposes.
samer@0 11 *
samer@0 12 \***********************************************************************/
samer@0 13
samer@0 14
samer@0 15 #include "RngStream.h"
samer@0 16 #include <stdio.h>
samer@0 17 #include <stdlib.h>
samer@0 18 #include <string.h>
samer@0 19 #include <math.h>
samer@0 20
samer@0 21 /*---------------------------------------------------------------------*/
samer@0 22 /* Private part. */
samer@0 23 /*---------------------------------------------------------------------*/
samer@0 24
samer@0 25 typedef struct rng_state *RngStream;
samer@0 26
samer@0 27 #define norm 2.328306549295727688e-10
samer@0 28 #define m1 4294967087.0
samer@0 29 #define m2 4294944443.0
samer@0 30 #define a12 1403580.0
samer@0 31 #define a13n 810728.0
samer@0 32 #define a21 527612.0
samer@0 33 #define a23n 1370589.0
samer@0 34
samer@0 35 #define two17 131072.0
samer@0 36 #define two53 9007199254740992.0
samer@0 37 #define fact 5.9604644775390625e-8 /* 1 / 2^24 */
samer@0 38
samer@0 39
samer@0 40
samer@0 41 /* Default initial seed */
samer@0 42 static double nextSeed[6] = { 12345, 12345, 12345, 12345, 12345, 12345 };
samer@0 43
samer@0 44
samer@0 45 /* The following are the transition matrices of the two MRG components */
samer@0 46 /* (in matrix form), raised to the powers 2^0, 2^76, and 2^127, resp.*/
samer@0 47
samer@0 48 static double A1p0[3][3] = {
samer@0 49 { 0.0, 1.0, 0.0 },
samer@0 50 { 0.0, 0.0, 1.0 },
samer@0 51 { -810728.0, 1403580.0, 0.0 }
samer@0 52 };
samer@0 53
samer@0 54 static double A2p0[3][3] = {
samer@0 55 { 0.0, 1.0, 0.0 },
samer@0 56 { 0.0, 0.0, 1.0 },
samer@0 57 { -1370589.0, 0.0, 527612.0 }
samer@0 58 };
samer@0 59
samer@0 60
samer@0 61 static double A1p76[3][3] = {
samer@0 62 { 82758667.0, 1871391091.0, 4127413238.0 },
samer@0 63 { 3672831523.0, 69195019.0, 1871391091.0 },
samer@0 64 { 3672091415.0, 3528743235.0, 69195019.0 }
samer@0 65 };
samer@0 66
samer@0 67 static double A2p76[3][3] = {
samer@0 68 { 1511326704.0, 3759209742.0, 1610795712.0 },
samer@0 69 { 4292754251.0, 1511326704.0, 3889917532.0 },
samer@0 70 { 3859662829.0, 4292754251.0, 3708466080.0 }
samer@0 71 };
samer@0 72
samer@0 73 static double A1p127[3][3] = {
samer@0 74 { 2427906178.0, 3580155704.0, 949770784.0 },
samer@0 75 { 226153695.0, 1230515664.0, 3580155704.0 },
samer@0 76 { 1988835001.0, 986791581.0, 1230515664.0 }
samer@0 77 };
samer@0 78
samer@0 79 static double A2p127[3][3] = {
samer@0 80 { 1464411153.0, 277697599.0, 1610723613.0 },
samer@0 81 { 32183930.0, 1464411153.0, 1022607788.0 },
samer@0 82 { 2824425944.0, 32183930.0, 2093834863.0 }
samer@0 83 };
samer@0 84
samer@0 85
samer@0 86
samer@0 87
samer@0 88
samer@0 89 /*-------------------------------------------------------------------------*/
samer@0 90
samer@0 91 static double MultModM (double a, double s, double c, double m)
samer@0 92 /* Compute (a*s + c) % m. m must be < 2^35. Works also for s, c < 0 */
samer@0 93 {
samer@0 94 double v;
samer@0 95 long a1;
samer@0 96 v = a * s + c;
samer@0 97 if ((v >= two53) || (v <= -two53)) {
samer@0 98 a1 = (long) (a / two17);
samer@0 99 a -= a1 * two17;
samer@0 100 v = a1 * s;
samer@0 101 a1 = (long) (v / m);
samer@0 102 v -= a1 * m;
samer@0 103 v = v * two17 + a * s + c;
samer@0 104 }
samer@0 105 a1 = (long) (v / m);
samer@0 106 if ((v -= a1 * m) < 0.0)
samer@0 107 return v += m;
samer@0 108 else
samer@0 109 return v;
samer@0 110 }
samer@0 111
samer@0 112
samer@0 113 /*-------------------------------------------------------------------------*/
samer@0 114
samer@0 115
samer@0 116 static void print_vec(double *p)
samer@0 117 {
samer@0 118 int i;
samer@0 119 for (i=0; i<6; i++) printf("%.0lf ",p[i]);
samer@0 120 printf("\n");
samer@0 121 }
samer@0 122
samer@0 123
samer@0 124 static void MatVecModM (double A[3][3], double s[3], double v[3], double m)
samer@0 125 /* Returns v = A*s % m. Assumes that -m < s[i] < m. */
samer@0 126 /* Works even if v = s. */
samer@0 127 {
samer@0 128 int i;
samer@0 129 double x[3];
samer@0 130 for (i = 0; i < 3; ++i) {
samer@0 131 x[i] = MultModM (A[i][0], s[0], 0.0, m);
samer@0 132 x[i] = MultModM (A[i][1], s[1], x[i], m);
samer@0 133 x[i] = MultModM (A[i][2], s[2], x[i], m);
samer@0 134 }
samer@0 135 memcpy(v,x,3*sizeof(double));
samer@0 136 }
samer@0 137
samer@0 138
samer@0 139 static void MatMatModM (double A[3][3], double B[3][3], double C[3][3],
samer@0 140 double m)
samer@0 141 /* Returns C = A*B % m. Work even if A = C or B = C or A = B = C. */
samer@0 142 {
samer@0 143 int i, j;
samer@0 144 double V[3], W[3][3];
samer@0 145 for (i = 0; i < 3; ++i) {
samer@0 146 for (j = 0; j < 3; ++j) V[j] = B[j][i];
samer@0 147 MatVecModM (A, V, V, m);
samer@0 148 for (j = 0; j < 3; ++j) W[j][i] = V[j];
samer@0 149 }
samer@0 150 memcpy(C,W,9*sizeof(double));
samer@0 151 }
samer@0 152
samer@0 153 static void MatTwoPowModM (double A[3][3], double B[3][3], double m, long e)
samer@0 154 /* Compute matrix B = (A^(2^e) % m); works even if A = B */
samer@0 155 {
samer@0 156 int i, j;
samer@0 157
samer@0 158 /* initialize: B = A */
samer@0 159 if (A != B) {
samer@0 160 for (i = 0; i < 3; i++) {
samer@0 161 for (j = 0; j < 3; ++j)
samer@0 162 B[i][j] = A[i][j];
samer@0 163 }
samer@0 164 }
samer@0 165 /* Compute B = A^{2^e} */
samer@0 166 for (i = 0; i < e; i++)
samer@0 167 MatMatModM (B, B, B, m);
samer@0 168 }
samer@0 169
samer@0 170
samer@0 171 /* returns the next integer in the sequence
samer@0 172 * new state goes in g1
samer@0 173 * g1 can be the same as g, resulting in
samer@0 174 * an update in place.
samer@0 175 */
samer@0 176 double next(RngStream g, RngStream g1)
samer@0 177 {
samer@0 178 double p1, p2;
samer@0 179
samer@0 180 // printf("before: "); print_vec(g->Cg);
samer@0 181 /* Component 1 */
samer@0 182 p1 = a12 * g->Cg[1] - a13n * g->Cg[0];
samer@0 183 p1 -= m1*floor(p1/m1);
samer@0 184 g1->Cg[0] = g->Cg[1];
samer@0 185 g1->Cg[1] = g->Cg[2];
samer@0 186 g1->Cg[2] = p1;
samer@0 187
samer@0 188 /* Component 2 */
samer@0 189 p2 = a21 * g->Cg[5] - a23n * g->Cg[3];
samer@0 190 p2 -= m2*floor(p2/m2);
samer@0 191 g1->Cg[3] = g->Cg[4];
samer@0 192 g1->Cg[4] = g->Cg[5];
samer@0 193 g1->Cg[5] = p2;
samer@0 194
samer@0 195 // printf("after: "); print_vec(g1->Cg);
samer@0 196 /* Combination */
samer@0 197 return (p1 > p2) ? (p1 - p2) : (p1 - p2 + m1);
samer@0 198 }
samer@0 199
samer@0 200
samer@0 201 /*-------------------------------------------------------------------------*/
samer@0 202 static int CheckSeed (unsigned seed[6])
samer@0 203 {
samer@0 204 /* Check that the seeds are legitimate values. Returns 0 if legal seeds,
samer@0 205 * i:1..6 if seed[i] is bad
samer@0 206 * 8 if seeds 1..3 are zero
samer@0 207 * 9 if seeds 4..6 are zero
samer@0 208 */
samer@0 209 int i;
samer@0 210
samer@0 211 for (i = 0; i < 3; ++i) {
samer@0 212 if (seed[i] >= m1) return i+1;
samer@0 213 }
samer@0 214 for (i = 3; i < 6; ++i) {
samer@0 215 if (seed[i] >= m2) return i+1;
samer@0 216 }
samer@0 217 if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) return 8;
samer@0 218 if (seed[3] == 0 && seed[4] == 0 && seed[5] == 0) return 9;
samer@0 219
samer@0 220 return 0;
samer@0 221 }
samer@0 222
samer@0 223
samer@0 224 /*---------------------------------------------------------------------*/
samer@0 225 /* Public part. */
samer@0 226 /*---------------------------------------------------------------------*/
samer@0 227
samer@0 228
samer@0 229 void RngStream_InitState(RngStream g) {
samer@0 230 memcpy(g->Cg,nextSeed,6*sizeof(double));
samer@0 231 //printf("init: "); print_vec(g->Cg);
samer@0 232 }
samer@0 233
samer@0 234 void RngStream_InitJump(struct rng_jump *j, int e)
samer@0 235 {
samer@0 236 void *a1, *a2;
samer@0 237
samer@0 238 if (e>=127) { a1=A1p127; a2=A2p127; e-=127; }
samer@0 239 else if (e==76) { a1=A1p76; a2=A2p76; e-=76; }
samer@0 240 else { a1=A1p0; a2=A2p0; }
samer@0 241
samer@0 242 memcpy(j->T1,a1,9*sizeof(double));
samer@0 243 memcpy(j->T2,a2,9*sizeof(double));
samer@0 244 MatTwoPowModM(j->T1,j->T1,m1,e);
samer@0 245 MatTwoPowModM(j->T2,j->T2,m2,e);
samer@0 246 }
samer@0 247
samer@0 248 void RngStream_DoubleJump(struct rng_jump *j1, struct rng_jump *j2)
samer@0 249 {
samer@0 250 MatMatModM(j1->T1,j1->T1,j2->T1,m1);
samer@0 251 MatMatModM(j1->T2,j1->T2,j2->T2,m2);
samer@0 252 }
samer@0 253
samer@0 254 void RngStream_Advance(struct rng_jump *j, RngStream g1, RngStream g2)
samer@0 255 {
samer@0 256 MatVecModM (j->T1, &g1->Cg[0], &g2->Cg[0], m1);
samer@0 257 MatVecModM (j->T2, &g1->Cg[3], &g2->Cg[3], m2);
samer@0 258 }
samer@0 259
samer@0 260 double RngStream_Float(RngStream g, RngStream g1) {
samer@0 261 return norm*next(g,g1);
samer@0 262 }
samer@0 263
samer@0 264 double RngStream_Double(RngStream g, RngStream g1) {
samer@0 265 double u = RngStream_Float(g,g1);
samer@0 266 u += fact*RngStream_Float(g1,g1);
samer@0 267 return (u < 1.0) ? u : (u - 1.0);
samer@0 268 }
samer@0 269
samer@0 270 double RngStream_Raw(RngStream g, RngStream g1) {
samer@0 271 return next(g,g1);
samer@0 272 }
samer@0 273
samer@0 274 /*-------------------------------------------------------------------------*/
samer@0 275
samer@0 276 int RngStream_SetState (RngStream g, unsigned seed[6])
samer@0 277 {
samer@0 278 int i;
samer@0 279 if (CheckSeed (seed))
samer@0 280 return -1; /* FAILURE */
samer@0 281 for (i = 0; i < 6; ++i)
samer@0 282 g->Cg[i] = (double)seed[i];
samer@0 283
samer@0 284 return 0; /* SUCCESS */
samer@0 285 }
samer@0 286
samer@0 287
samer@0 288 void RngStream_GetState (RngStream g, unsigned seed[6])
samer@0 289 {
samer@0 290 int i;
samer@0 291 for (i = 0; i < 6; ++i) seed[i] = (unsigned)g->Cg[i];
samer@0 292 }
samer@0 293