mirror of
https://github.com/postgres/postgres.git
synced 2025-10-22 14:32:25 +03:00
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
This commit is contained in:
@@ -42,7 +42,6 @@ OBJS = \
|
||||
$(PG_CRC32C_OBJS) \
|
||||
bsearch_arg.o \
|
||||
chklocale.o \
|
||||
erand48.o \
|
||||
inet_net_ntop.o \
|
||||
noblock.o \
|
||||
path.o \
|
||||
|
@@ -1,136 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* erand48.c
|
||||
*
|
||||
* This file supplies pg_erand48() and related functions, which except
|
||||
* for the names are just like the POSIX-standard erand48() family.
|
||||
* (We don't supply the full set though, only the ones we have found use
|
||||
* for in Postgres. In particular, we do *not* implement lcong48(), so
|
||||
* that there is no need for the multiplier and addend to be variable.)
|
||||
*
|
||||
* We used to test for an operating system version rather than
|
||||
* unconditionally using our own, but (1) some versions of Cygwin have a
|
||||
* buggy erand48() that always returns zero and (2) as of 2011, glibc's
|
||||
* erand48() is strangely coded to be almost-but-not-quite thread-safe,
|
||||
* which doesn't matter for the backend but is important for pgbench.
|
||||
*
|
||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
||||
*
|
||||
* Portions Copyright (c) 1993 Martin Birgmeier
|
||||
* All rights reserved.
|
||||
*
|
||||
* You may redistribute unmodified or modified versions of this source
|
||||
* code provided that the above copyright notice and this and the
|
||||
* following conditions are retained.
|
||||
*
|
||||
* This software is provided ``as is'', and comes with no warranties
|
||||
* of any kind. I shall in no event be liable for anything that happens
|
||||
* to anyone/anything when using this software.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/port/erand48.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "c.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* These values are specified by POSIX */
|
||||
#define RAND48_MULT UINT64CONST(0x0005deece66d)
|
||||
#define RAND48_ADD UINT64CONST(0x000b)
|
||||
|
||||
/* POSIX specifies 0x330e's use in srand48, but the other bits are arbitrary */
|
||||
#define RAND48_SEED_0 (0x330e)
|
||||
#define RAND48_SEED_1 (0xabcd)
|
||||
#define RAND48_SEED_2 (0x1234)
|
||||
|
||||
static unsigned short _rand48_seed[3] = {
|
||||
RAND48_SEED_0,
|
||||
RAND48_SEED_1,
|
||||
RAND48_SEED_2
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Advance the 48-bit value stored in xseed[] to the next "random" number.
|
||||
*
|
||||
* Also returns the value of that number --- without masking it to 48 bits.
|
||||
* If caller uses the result, it must mask off the bits it wants.
|
||||
*/
|
||||
static uint64
|
||||
_dorand48(unsigned short xseed[3])
|
||||
{
|
||||
/*
|
||||
* We do the arithmetic in uint64; any type wider than 48 bits would work.
|
||||
*/
|
||||
uint64 in;
|
||||
uint64 out;
|
||||
|
||||
in = (uint64) xseed[2] << 32 | (uint64) xseed[1] << 16 | (uint64) xseed[0];
|
||||
|
||||
out = in * RAND48_MULT + RAND48_ADD;
|
||||
|
||||
xseed[0] = out & 0xFFFF;
|
||||
xseed[1] = (out >> 16) & 0xFFFF;
|
||||
xseed[2] = (out >> 32) & 0xFFFF;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate a random floating-point value using caller-supplied state.
|
||||
* Values are uniformly distributed over the interval [0.0, 1.0).
|
||||
*/
|
||||
double
|
||||
pg_erand48(unsigned short xseed[3])
|
||||
{
|
||||
uint64 x = _dorand48(xseed);
|
||||
|
||||
return ldexp((double) (x & UINT64CONST(0xFFFFFFFFFFFF)), -48);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a random non-negative integral value using internal state.
|
||||
* Values are uniformly distributed over the interval [0, 2^31).
|
||||
*/
|
||||
long
|
||||
pg_lrand48(void)
|
||||
{
|
||||
uint64 x = _dorand48(_rand48_seed);
|
||||
|
||||
return (x >> 17) & UINT64CONST(0x7FFFFFFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a random signed integral value using caller-supplied state.
|
||||
* Values are uniformly distributed over the interval [-2^31, 2^31).
|
||||
*/
|
||||
long
|
||||
pg_jrand48(unsigned short xseed[3])
|
||||
{
|
||||
uint64 x = _dorand48(xseed);
|
||||
|
||||
return (int32) ((x >> 16) & UINT64CONST(0xFFFFFFFF));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the internal state using the given seed.
|
||||
*
|
||||
* Per POSIX, this uses only 32 bits from "seed" even if "long" is wider.
|
||||
* Hence, the set of possible seed values is smaller than it could be.
|
||||
* Better practice is to use caller-supplied state and initialize it with
|
||||
* random bits obtained from a high-quality source of random bits.
|
||||
*
|
||||
* Note: POSIX specifies a function seed48() that allows all 48 bits
|
||||
* of the internal state to be set, but we don't currently support that.
|
||||
*/
|
||||
void
|
||||
pg_srand48(long seed)
|
||||
{
|
||||
_rand48_seed[0] = RAND48_SEED_0;
|
||||
_rand48_seed[1] = (unsigned short) seed;
|
||||
_rand48_seed[2] = (unsigned short) (seed >> 16);
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* random.c
|
||||
* random() wrapper
|
||||
*
|
||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/port/random.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "c.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
long
|
||||
random(void)
|
||||
{
|
||||
return pg_lrand48();
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* srandom.c
|
||||
* srandom() wrapper
|
||||
*
|
||||
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/port/srandom.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "c.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
void
|
||||
srandom(unsigned int seed)
|
||||
{
|
||||
pg_srand48((long int) seed);
|
||||
}
|
Reference in New Issue
Block a user