From 3804539e48e794781c6145c7f988f5d507418fa8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 28 Nov 2021 21:32:36 -0500 Subject: Replace random(), pg_erand48(), etc with a better PRNG API and algorithm. Standardize on xoroshiro128** as our basic PRNG algorithm, eliminating a bunch of platform dependencies as well as fundamentally-obsolete PRNG code. In addition, this API replacement will ease replacing the algorithm again in future, should that become necessary. xoroshiro128** is a few percent slower than the drand48 family, but it can produce full-width 64-bit random values not only 48-bit, and it should be much more trustworthy. It's likely to be noticeably faster than the platform's random(), depending on which platform you are thinking about; and we can have non-global state vectors easily, unlike with random(). It is not cryptographically strong, but neither are the functions it replaces. Fabien Coelho, reviewed by Dean Rasheed, Aleksander Alekseev, and myself Discussion: https://postgr.es/m/alpine.DEB.2.22.394.2105241211230.165418@pseudo --- src/backend/utils/adt/float.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'src/backend/utils/adt/float.c') diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 098bbb372bf..455e5d8cbea 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -21,6 +21,7 @@ #include "catalog/pg_type.h" #include "common/int.h" +#include "common/pg_prng.h" #include "common/shortest_dec.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -65,7 +66,7 @@ float8 degree_c_one = 1.0; /* State for drandom() and setseed() */ static bool drandom_seed_set = false; -static unsigned short drandom_seed[3] = {0, 0, 0}; +static pg_prng_state drandom_seed; /* Local function prototypes */ static double sind_q1(double x); @@ -2762,22 +2763,20 @@ drandom(PG_FUNCTION_ARGS) * Should that fail for some reason, we fall back on a lower-quality * seed based on current time and PID. */ - if (!pg_strong_random(drandom_seed, sizeof(drandom_seed))) + if (unlikely(!pg_prng_strong_seed(&drandom_seed))) { TimestampTz now = GetCurrentTimestamp(); uint64 iseed; /* Mix the PID with the most predictable bits of the timestamp */ iseed = (uint64) now ^ ((uint64) MyProcPid << 32); - drandom_seed[0] = (unsigned short) iseed; - drandom_seed[1] = (unsigned short) (iseed >> 16); - drandom_seed[2] = (unsigned short) (iseed >> 32); + pg_prng_seed(&drandom_seed, iseed); } drandom_seed_set = true; } - /* pg_erand48 produces desired result range [0.0 - 1.0) */ - result = pg_erand48(drandom_seed); + /* pg_prng_double produces desired result range [0.0 - 1.0) */ + result = pg_prng_double(&drandom_seed); PG_RETURN_FLOAT8(result); } @@ -2790,7 +2789,6 @@ Datum setseed(PG_FUNCTION_ARGS) { float8 seed = PG_GETARG_FLOAT8(0); - uint64 iseed; if (seed < -1 || seed > 1 || isnan(seed)) ereport(ERROR, @@ -2798,11 +2796,7 @@ setseed(PG_FUNCTION_ARGS) errmsg("setseed parameter %g is out of allowed range [-1,1]", seed))); - /* Use sign bit + 47 fractional bits to fill drandom_seed[] */ - iseed = (int64) (seed * (float8) UINT64CONST(0x7FFFFFFFFFFF)); - drandom_seed[0] = (unsigned short) iseed; - drandom_seed[1] = (unsigned short) (iseed >> 16); - drandom_seed[2] = (unsigned short) (iseed >> 32); + pg_prng_fseed(&drandom_seed, seed); drandom_seed_set = true; PG_RETURN_VOID(); -- cgit v1.2.3