GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
lrand48.c
Go to the documentation of this file.
1 /*!
2  * \file lib/gis/lrand48.c
3  *
4  * \brief GIS Library - Pseudo-random number generation
5  *
6  * (C) 2014 by the GRASS Development Team
7  *
8  * This program is free software under the GNU General Public License
9  * (>=v2). Read the file COPYING that comes with GRASS for details.
10  *
11  * \author Glynn Clements
12  */
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
18 
19 #include <grass/gis.h>
20 #include <grass/glocale.h>
21 
22 #ifdef HAVE_GETTIMEOFDAY
23 #include <sys/time.h>
24 #else
25 #include <time.h>
26 #endif
27 
28 #include <sys/types.h>
29 #include <unistd.h>
30 
31 typedef unsigned short uint16;
32 typedef unsigned int uint32;
33 typedef signed int int32;
34 
35 static uint16 x0, x1, x2;
36 static const uint32 a0 = 0xE66D;
37 static const uint32 a1 = 0xDEEC;
38 static const uint32 a2 = 0x5;
39 
40 static const uint32 b0 = 0xB;
41 
42 static int seeded;
43 
44 #define LO(x) ((x) & 0xFFFFU)
45 #define HI(x) ((x) >> 16)
46 
47 /*!
48  * \brief Seed the pseudo-random number generator
49  *
50  * \param[in] seedval 32-bit integer used to seed the PRNG
51  */
52 void G_srand48(long seedval)
53 {
54  uint32 x = (uint32) * (unsigned long *)&seedval;
55 
56  x2 = (uint16)HI(x);
57  x1 = (uint16)LO(x);
58  x0 = (uint16)0x330E;
59  seeded = 1;
60 }
61 
62 /*!
63  * \brief Seed the pseudo-random number generator from the time and PID
64  *
65  * A weak hash of the current time and PID is generated and used to
66  * seed the PRNG
67  *
68  * \return generated seed value passed to G_srand48()
69  */
70 long G_srand48_auto(void)
71 {
72  unsigned long seed;
73  char *grass_random_seed = getenv("GRASS_RANDOM_SEED");
74 
75  if (!grass_random_seed)
76  grass_random_seed = getenv("SOURCE_DATE_EPOCH");
77  if (grass_random_seed) {
78  seed = strtoull(grass_random_seed, NULL, 10);
79  }
80  else {
81  seed = (unsigned long)getpid();
82 
83 #ifdef HAVE_GETTIMEOFDAY
84  {
85  struct timeval tv;
86 
87  if (gettimeofday(&tv, NULL) < 0)
88  G_fatal_error(_("gettimeofday failed: %s"), strerror(errno));
89  seed += (unsigned long)tv.tv_sec;
90  seed += (unsigned long)tv.tv_usec;
91  }
92 #else
93  {
94  time_t t = time(NULL);
95 
96  seed += (unsigned long)t;
97  }
98 #endif
99  }
100 
101  G_srand48((long)seed);
102  return (long)seed;
103 }
104 
105 static void G__next(void)
106 {
107  uint32 a0x0 = a0 * x0;
108  uint32 a0x1 = a0 * x1;
109  uint32 a0x2 = a0 * x2;
110  uint32 a1x0 = a1 * x0;
111  uint32 a1x1 = a1 * x1;
112  uint32 a2x0 = a2 * x0;
113 
114  uint32 y0 = LO(a0x0) + b0;
115  uint32 y1 = LO(a0x1) + LO(a1x0) + HI(a0x0);
116  uint32 y2 = LO(a0x2) + LO(a1x1) + LO(a2x0) + HI(a0x1) + HI(a1x0);
117 
118  if (!seeded)
119  G_fatal_error(_("Pseudo-random number generator not seeded"));
120 
121  x0 = (uint16)LO(y0);
122  y1 += HI(y0);
123  x1 = (uint16)LO(y1);
124  y2 += HI(y1);
125  x2 = (uint16)LO(y2);
126 }
127 
128 /*!
129  * \brief Generate an integer in the range [0, 2^31)
130  *
131  * \return the generated value
132  */
133 long G_lrand48(void)
134 {
135  uint32 r;
136 
137  G__next();
138  r = ((uint32)x2 << 15) | ((uint32)x1 >> 1);
139  return (long)r;
140 }
141 
142 /*!
143  * \brief Generate an integer in the range [-2^31, 2^31)
144  *
145  * \return the generated value
146  */
147 long G_mrand48(void)
148 {
149  uint32 r;
150 
151  G__next();
152  r = ((uint32)x2 << 16) | ((uint32)x1);
153  return (long)(int32)r;
154 }
155 
156 /*!
157  * \brief Generate a floating-point value in the range [0,1)
158  *
159  * \return the generated value
160  */
161 double G_drand48(void)
162 {
163  double r = 0.0;
164 
165  G__next();
166  r += x2;
167  r *= 0x10000;
168  r += x1;
169  r *= 0x10000;
170  r += x0;
171  r /= 281474976710656.0; /* 2^48 */
172  return r;
173 }
174 
175 /*
176 
177  Test program
178 
179  int main(int argc, char **argv)
180  {
181  long s = (argc > 1) ? atol(argv[1]) : 0;
182  int i;
183 
184  srand48(s);
185  G_srand48(s);
186 
187  for (i = 0; i < 100; i++) {
188  printf("%.50f %.50f\n", drand48(), G_drand48());
189  printf("%lu %lu\n", lrand48(), G_lrand48());
190  printf("%ld %ld\n", mrand48(), G_mrand48());
191  }
192 
193  return 0;
194  }
195 
196  */
#define NULL
Definition: ccmath.h:32
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define _(str)
Definition: glocale.h:10
unsigned short uint16
Definition: lrand48.c:31
unsigned int uint32
Definition: lrand48.c:32
long G_mrand48(void)
Generate an integer in the range [-2^31, 2^31)
Definition: lrand48.c:147
long G_lrand48(void)
Generate an integer in the range [0, 2^31)
Definition: lrand48.c:133
long G_srand48_auto(void)
Seed the pseudo-random number generator from the time and PID.
Definition: lrand48.c:70
signed int int32
Definition: lrand48.c:33
#define HI(x)
Definition: lrand48.c:45
void G_srand48(long seedval)
Seed the pseudo-random number generator.
Definition: lrand48.c:52
#define LO(x)
Definition: lrand48.c:44
double G_drand48(void)
Generate a floating-point value in the range [0,1)
Definition: lrand48.c:161
double t
Definition: r_raster.c:39
double r
Definition: r_raster.c:39
int gettimeofday(struct timeval *, struct timezone *)
#define getpid
Definition: unistd.h:20
#define x