mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-14 13:09:45 +02:00
97c39498e5
Backpatch-through: certain files through 9.4
137 lines
3.9 KiB
C
137 lines
3.9 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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-2019, 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);
|
|
}
|