-
Notifications
You must be signed in to change notification settings - Fork 0
/
RNG.cc
executable file
·142 lines (124 loc) · 3.9 KB
/
RNG.cc
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// This may look like C code, but it is really -*- C++ -*-
/*
Copyright (C) 1989 Free Software Foundation
This file is part of the GNU C++ Library. This library is free
software; you can redistribute it and/or modify it under the terms of
the GNU Library General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version. This library is distributed in the hope
that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef __GNUG__
#pragma implementation
#endif
#include <assert.h>
//#include <builtin.h>
#include "RNG.h"
// These two static fields get initialized by RNG::RNG().
PrivateRNGSingleType RNG::singleMantissa;
PrivateRNGDoubleType RNG::doubleMantissa;
//
// The scale constant is 2^-31. It is used to scale a 31 bit
// long to a double.
//
//static const double randomDoubleScaleConstant = 4.656612873077392578125e-10;
//static const float randomFloatScaleConstant = 4.656612873077392578125e-10;
static char initialized = 0;
RNG::RNG()
{
if (!initialized)
{
#if 0 /* Nonsense! */
assert (sizeof(double) == 2 * sizeof(_G_uint32_t));
#endif
//
// The following is a hack that I attribute to
// Andres Nowatzyk at CMU. The intent of the loop
// is to form the smallest number 0 <= x < 1.0,
// which is then used as a mask for two longwords.
// this gives us a fast way way to produce double
// precision numbers from longwords.
//
// I know that this works for IEEE and VAX floating
// point representations.
//
// A further complication is that gnu C will blow
// the following loop, unless compiled with -ffloat-store,
// because it uses extended representations for some of
// of the comparisons. Thus, we have the following hack.
// If we could specify #pragma optimize, we wouldn't need this.
//
PrivateRNGDoubleType t;
PrivateRNGSingleType s;
#if _IEEE == 1
t.d = 1.5;
if ( t.u[1] == 0 ) { // sun word order?
t.u[0] = 0x3fffffff;
t.u[1] = 0xffffffff;
}
else {
t.u[0] = 0xffffffff; // encore word order?
t.u[1] = 0x3fffffff;
}
s.u = 0x3fffffff;
#else
volatile double x = 1.0; // volatile needed when fp hardware used,
// and has greater precision than memory doubles
double y = 0.5;
do { // find largest fp-number < 2.0
t.d = x;
x += y;
y *= 0.5;
} while (x != t.d && x < 2.0);
volatile float xx = 1.0; // volatile needed when fp hardware used,
// and has greater precision than memory floats
float yy = 0.5;
do { // find largest fp-number < 2.0
s.s = xx;
xx += yy;
yy *= 0.5;
} while (xx != s.s && xx < 2.0);
#endif
if (sizeof(double) > sizeof (float))
{
// set doubleMantissa to 1 for each doubleMantissa bit
doubleMantissa.d = 1.0;
doubleMantissa.u[0] ^= t.u[0];
doubleMantissa.u[1] ^= t.u[1];
}
// set singleMantissa to 1 for each singleMantissa bit
singleMantissa.s = 1.0;
singleMantissa.u ^= s.u;
initialized = 1;
}
}
float RNG::asFloat()
{
PrivateRNGSingleType result;
result.s = 1.0;
result.u |= (asLong() & singleMantissa.u);
result.s -= 1.0;
assert( result.s < 1.0 && result.s >= 0);
return( result.s );
}
double RNG::asDouble()
{
if (sizeof(float) == sizeof(double))
{
float result = asFloat();
asLong();
return result;
}
PrivateRNGDoubleType result;
result.d = 1.0;
result.u[0] |= (asLong() & doubleMantissa.u[0]);
result.u[1] |= (asLong() & doubleMantissa.u[1]);
result.d -= 1.0;
assert( result.d < 1.0 && result.d >= 0);
return( result.d );
}