-
Notifications
You must be signed in to change notification settings - Fork 0
/
nas_rand.c
118 lines (105 loc) · 3.07 KB
/
nas_rand.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "nas_rand.h"
#define _nas_rand_A 1220703125.00
/******************************************************************************
C
FUNCTION RANDLC (X, A)
C
C This routine returns a uniform pseudorandom double precision number in the
C range (0, 1) by using the linear congruential generator
C
C x_{k+1} = a x_k (mod 2^46)
C
C where 0 < x_k < 2^46 and 0 < a < 2^46. This scheme generates 2^44 numbers
C before repeating. The argument A is the same as 'a' in the above formula,
C and X is the same as x_0. A and X must be odd double precision integers
C in the range (1, 2^46). The returned value RANDLC is normalized to be
C between 0 and 1, i.e. RANDLC = 2^(-46) * x_1. X is updated to contain
C the new seed x_1, so that subsequent calls to RANDLC using the same
C arguments will generate a continuous sequence.
C
C This routine should produce the same results on any computer with at least
C 48 mantissa bits in double precision floating point data. On Cray systems,
C double precision should be disabled.
C
C David H. Bailey October 26, 1990
C
IMPLICIT DOUBLE PRECISION (A-H, O-Z)
SAVE KS, R23, R46, T23, T46
DATA KS/0/
C
C If this is the first call to RANDLC, compute R23 = 2 ^ -23, R46 = 2 ^ -46,
C T23 = 2 ^ 23, and T46 = 2 ^ 46. These are computed in loops, rather than
C by merely using the ** operator, in order to insure that the results are
C exact on all systems. This code assumes that 0.5D0 is represented exactly.
C
******************************************************************************/
double randlc(double *X)
{
static int KS;
static double R23, R46, T23, T46;
double T1, T2, T3, T4;
double A1;
double A2;
double X1;
double X2;
double Z;
int i, j;
if (KS == 0)
{
R23 = 1.0;
R46 = 1.0;
T23 = 1.0;
T46 = 1.0;
for (i=1; i<=23; i++)
{
R23 = 0.50 * R23;
T23 = 2.0 * T23;
}
for (i=1; i<=46; i++)
{
R46 = 0.50 * R46;
T46 = 2.0 * T46;
}
KS = 1;
}
/*
| Break A into two parts such that A = 2^23 * A1 + A2 and set X = N.
*/
T1 = R23 * _nas_rand_A;
j = T1;
A1 = j;
A2 = _nas_rand_A - T23 * A1;
/*
| Break X into two parts such that X = 2^23 * X1 + X2, compute
| Z = A1 * X2 + A2 * X1 (mod 2^23), and then
| X = 2^23 * Z + A2 * X2 (mod 2^46).
*/
T1 = R23 * *X;
j = T1;
X1 = j;
X2 = *X - T23 * X1;
T1 = A1 * X2 + A2 * X1;
j = R23 * T1;
T2 = j;
Z = T1 - T23 * T2;
T3 = T23 * Z + A2 * X2;
j = R46 * T3;
T4 = j;
*X = T3 - T46 * T4;
return(R46 * *X);
}
static double _nas_rand_seed;
#define _NAS_BITS 19
void nas_srand() {
_nas_rand_seed = 314159265.00;
}
int nas_rand() {
register int k;
double x;
k = (1<<_NAS_BITS) / 4;
x = randlc(&_nas_rand_seed);
x += randlc(&_nas_rand_seed);
x += randlc(&_nas_rand_seed);
x += randlc(&_nas_rand_seed);
return (k*x);
}