Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/common/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 7 kB image not shown  

Quelle  pg_prng.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * Pseudo-Random Number Generator
 *
 * We use Blackman and Vigna's xoroshiro128** 1.0 algorithm
 * to have a small, fast PRNG suitable for generating reasonably
 * good-quality 64-bit data.  This should not be considered
 * cryptographically strong, however.
 *
 * About these generators: https://prng.di.unimi.it/
 * See also https://en.wikipedia.org/wiki/List_of_random_number_generators
 *
 * Copyright (c) 2021-2025, PostgreSQL Global Development Group
 *
 * src/common/pg_prng.c
 *
 *-------------------------------------------------------------------------
 */


#include "c.h"

#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;


/*
 * 64-bit rotate left
 */

static inline uint64
rotl(uint64 x, int bits)
{
 return (x << bits) | (x >> (64 - bits));
}

/*
 * The basic xoroshiro128** algorithm.
 * Generates and returns a 64-bit uniformly distributed number,
 * updating the state vector for next time.
 *
 * Note: the state vector must not be all-zeroes, as that is a fixed point.
 */

static uint64
xoroshiro128ss(pg_prng_state *state)
{
 uint64  s0 = state->s0,
    sx = state->s1 ^ s0,
    val = rotl(s0 * 57) * 9;

 /* update state */
 state->s0 = rotl(s0, 24) ^ sx ^ (sx << 16);
 state->s1 = rotl(sx, 37);

 return val;
}

/*
 * We use this generator just to fill the xoroshiro128** state vector
 * from a 64-bit seed.
 */

static uint64
splitmix64(uint64 *state)
{
 /* state update */
 uint64  val = (*state += UINT64CONST(0x9E3779B97f4A7C15));

 /* value extraction */
 val = (val ^ (val >> 30)) * UINT64CONST(0xBF58476D1CE4E5B9);
 val = (val ^ (val >> 27)) * UINT64CONST(0x94D049BB133111EB);

 return val ^ (val >> 31);
}

/*
 * Initialize the PRNG state from a 64-bit integer,
 * taking care that we don't produce all-zeroes.
 */

void
pg_prng_seed(pg_prng_state *state, uint64 seed)
{
 state->s0 = splitmix64(&seed);
 state->s1 = splitmix64(&seed);
 /* Let's just make sure we didn't get all-zeroes */
 (void) pg_prng_seed_check(state);
}

/*
 * Initialize the PRNG state from a double in the range [-1.0, 1.0],
 * taking care that we don't produce all-zeroes.
 */

void
pg_prng_fseed(pg_prng_state *state, double fseed)
{
 /* Assume there's about 52 mantissa bits; the sign contributes too. */
 int64  seed = ((double) ((UINT64CONST(1) << 52) - 1)) * fseed;

 pg_prng_seed(state, (uint64) seed);
}

/*
 * Validate a PRNG seed value.
 */

bool
pg_prng_seed_check(pg_prng_state *state)
{
 /*
  * If the seeding mechanism chanced to produce all-zeroes, insert
  * something nonzero.  Anything would do; use Knuth's LCG parameters.
 */

 if (unlikely(state->s0 == 0 && state->s1 == 0))
 {
  state->s0 = UINT64CONST(0x5851F42D4C957F2D);
  state->s1 = UINT64CONST(0x14057B7EF767814F);
 }

 /* As a convenience for the pg_prng_strong_seed macro, return true */
 return true;
}

/*
 * Select a random uint64 uniformly from the range [0, PG_UINT64_MAX].
 */

uint64
pg_prng_uint64(pg_prng_state *state)
{
 return xoroshiro128ss(state);
}

/*
 * Select a random uint64 uniformly from the range [rmin, rmax].
 * If the range is empty, rmin is always produced.
 */

uint64
pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
{
 uint64  val;

 if (likely(rmax > rmin))
 {
  /*
   * Use bitmask rejection method to generate an offset in 0..range.
   * Each generated val is less than twice "range", so on average we
   * should not have to iterate more than twice.
 */

  uint64  range = rmax - rmin;
  uint32  rshift = 63 - pg_leftmost_one_pos64(range);

  do
  {
   val = xoroshiro128ss(state) >> rshift;
  } while (val > range);
 }
 else
  val = 0;

 return rmin + val;
}

/*
 * Select a random int64 uniformly from the range [PG_INT64_MIN, PG_INT64_MAX].
 */

int64
pg_prng_int64(pg_prng_state *state)
{
 return (int64) xoroshiro128ss(state);
}

/*
 * Select a random int64 uniformly from the range [0, PG_INT64_MAX].
 */

int64
pg_prng_int64p(pg_prng_state *state)
{
 return (int64) (xoroshiro128ss(state) & UINT64CONST(0x7FFFFFFFFFFFFFFF));
}

/*
 * Select a random int64 uniformly from the range [rmin, rmax].
 * If the range is empty, rmin is always produced.
 */

int64
pg_prng_int64_range(pg_prng_state *state, int64 rmin, int64 rmax)
{
 int64  val;

 if (likely(rmax > rmin))
 {
  uint64  uval;

  /*
   * Use pg_prng_uint64_range().  Can't simply pass it rmin and rmax,
   * since (uint64) rmin will be larger than (uint64) rmax if rmin < 0.
 */

  uval = (uint64) rmin +
   pg_prng_uint64_range(state, 0, (uint64) rmax - (uint64) rmin);

  /*
   * Safely convert back to int64, avoiding implementation-defined
   * behavior for values larger than PG_INT64_MAX.  Modern compilers
   * will reduce this to a simple assignment.
 */

  if (uval > PG_INT64_MAX)
   val = (int64) (uval - PG_INT64_MIN) + PG_INT64_MIN;
  else
   val = (int64) uval;
 }
 else
  val = rmin;

 return val;
}

/*
 * Select a random uint32 uniformly from the range [0, PG_UINT32_MAX].
 */

uint32
pg_prng_uint32(pg_prng_state *state)
{
 /*
  * Although xoroshiro128** is not known to have any weaknesses in
  * randomness of low-order bits, we prefer to use the upper bits of its
  * result here and below.
 */

 uint64  v = xoroshiro128ss(state);

 return (uint32) (v >> 32);
}

/*
 * Select a random int32 uniformly from the range [PG_INT32_MIN, PG_INT32_MAX].
 */

int32
pg_prng_int32(pg_prng_state *state)
{
 uint64  v = xoroshiro128ss(state);

 return (int32) (v >> 32);
}

/*
 * Select a random int32 uniformly from the range [0, PG_INT32_MAX].
 */

int32
pg_prng_int32p(pg_prng_state *state)
{
 uint64  v = xoroshiro128ss(state);

 return (int32) (v >> 33);
}

/*
 * Select a random double uniformly from the range [0.0, 1.0).
 *
 * Note: if you want a result in the range (0.0, 1.0], the standard way
 * to get that is "1.0 - pg_prng_double(state)".
 */

double
pg_prng_double(pg_prng_state *state)
{
 uint64  v = xoroshiro128ss(state);

 /*
  * As above, assume there's 52 mantissa bits in a double.  This result
  * could round to 1.0 if double's precision is less than that; but we
  * assume IEEE float arithmetic elsewhere in Postgres, so this seems OK.
 */

 return ldexp((double) (v >> (64 - 52)), -52);
}

/*
 * 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
pg_prng_bool(pg_prng_state *state)
{
 uint64  v = xoroshiro128ss(state);

 return (bool) (v >> 63);
}

Messung V0.5 in Prozent
C=64 H=94 G=80

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-08-09) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.