summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorTom Lane2023-01-09 17:44:00 +0000
committerTom Lane2023-01-09 17:44:00 +0000
commit38d81760c4d7e22b95252e3545596602c9e38806 (patch)
treec5f8802619bf418dbdcc40392bb6d47123861908 /src/common
parent2673ebf49acfd83b09c777ced8f21eacd27b51ce (diff)
Invent random_normal() to provide normally-distributed random numbers.
There is already a version of this in contrib/tablefunc, but it seems sufficiently widely useful to justify having it in core. Paul Ramsey Discussion: https://postgr.es/m/CACowWR0DqHAvOKUCNxTrASFkWsDLqKMd6WiXvVvaWg4pV1BMnQ@mail.gmail.com
Diffstat (limited to 'src/common')
-rw-r--r--src/common/pg_prng.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/src/common/pg_prng.c b/src/common/pg_prng.c
index e58b471cff..c7bb92ede3 100644
--- a/src/common/pg_prng.c
+++ b/src/common/pg_prng.c
@@ -19,11 +19,17 @@
#include "c.h"
-#include <math.h> /* for ldexp() */
+#include <math.h>
#include "common/pg_prng.h"
#include "port/pg_bitutils.h"
+/* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
/* process-wide state vector */
pg_prng_state pg_global_prng_state;
@@ -236,6 +242,35 @@ pg_prng_double(pg_prng_state *state)
}
/*
+ * Select a random double from the normal distribution with
+ * mean = 0.0 and stddev = 1.0.
+ *
+ * To get a result from a different normal distribution use
+ * STDDEV * pg_prng_double_normal() + MEAN
+ *
+ * Uses https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
+ */
+double
+pg_prng_double_normal(pg_prng_state *state)
+{
+ double u1,
+ u2,
+ z0;
+
+ /*
+ * pg_prng_double generates [0, 1), but for the basic version of the
+ * Box-Muller transform the two uniformly distributed random numbers are
+ * expected to be in (0, 1]; in particular we'd better not compute log(0).
+ */
+ u1 = 1.0 - pg_prng_double(state);
+ u2 = 1.0 - pg_prng_double(state);
+
+ /* Apply Box-Muller transform to get one normal-valued output */
+ z0 = sqrt(-2.0 * log(u1)) * sin(2.0 * M_PI * u2);
+ return z0;
+}
+
+/*
* Select a random boolean value.
*/
bool