LCOV - code coverage report
Current view: top level - src/port - erand48.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 16 21 76.2 %
Date: 2019-11-15 22:06:47 Functions: 4 5 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * erand48.c
       4             :  *
       5             :  * This file supplies pg_erand48() and related functions, which except
       6             :  * for the names are just like the POSIX-standard erand48() family.
       7             :  * (We don't supply the full set though, only the ones we have found use
       8             :  * for in Postgres.  In particular, we do *not* implement lcong48(), so
       9             :  * that there is no need for the multiplier and addend to be variable.)
      10             :  *
      11             :  * We used to test for an operating system version rather than
      12             :  * unconditionally using our own, but (1) some versions of Cygwin have a
      13             :  * buggy erand48() that always returns zero and (2) as of 2011, glibc's
      14             :  * erand48() is strangely coded to be almost-but-not-quite thread-safe,
      15             :  * which doesn't matter for the backend but is important for pgbench.
      16             :  *
      17             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      18             :  *
      19             :  * Portions Copyright (c) 1993 Martin Birgmeier
      20             :  * All rights reserved.
      21             :  *
      22             :  * You may redistribute unmodified or modified versions of this source
      23             :  * code provided that the above copyright notice and this and the
      24             :  * following conditions are retained.
      25             :  *
      26             :  * This software is provided ``as is'', and comes with no warranties
      27             :  * of any kind. I shall in no event be liable for anything that happens
      28             :  * to anyone/anything when using this software.
      29             :  *
      30             :  * IDENTIFICATION
      31             :  *    src/port/erand48.c
      32             :  *
      33             :  *-------------------------------------------------------------------------
      34             :  */
      35             : 
      36             : #include "c.h"
      37             : 
      38             : #include <math.h>
      39             : 
      40             : /* These values are specified by POSIX */
      41             : #define RAND48_MULT     UINT64CONST(0x0005deece66d)
      42             : #define RAND48_ADD      UINT64CONST(0x000b)
      43             : 
      44             : /* POSIX specifies 0x330e's use in srand48, but the other bits are arbitrary */
      45             : #define RAND48_SEED_0   (0x330e)
      46             : #define RAND48_SEED_1   (0xabcd)
      47             : #define RAND48_SEED_2   (0x1234)
      48             : 
      49             : static unsigned short _rand48_seed[3] = {
      50             :     RAND48_SEED_0,
      51             :     RAND48_SEED_1,
      52             :     RAND48_SEED_2
      53             : };
      54             : 
      55             : 
      56             : /*
      57             :  * Advance the 48-bit value stored in xseed[] to the next "random" number.
      58             :  *
      59             :  * Also returns the value of that number --- without masking it to 48 bits.
      60             :  * If caller uses the result, it must mask off the bits it wants.
      61             :  */
      62             : static uint64
      63     5393592 : _dorand48(unsigned short xseed[3])
      64             : {
      65             :     /*
      66             :      * We do the arithmetic in uint64; any type wider than 48 bits would work.
      67             :      */
      68             :     uint64      in;
      69             :     uint64      out;
      70             : 
      71     5393592 :     in = (uint64) xseed[2] << 32 | (uint64) xseed[1] << 16 | (uint64) xseed[0];
      72             : 
      73     5393592 :     out = in * RAND48_MULT + RAND48_ADD;
      74             : 
      75     5393592 :     xseed[0] = out & 0xFFFF;
      76     5393592 :     xseed[1] = (out >> 16) & 0xFFFF;
      77     5393592 :     xseed[2] = (out >> 32) & 0xFFFF;
      78             : 
      79     5393592 :     return out;
      80             : }
      81             : 
      82             : 
      83             : /*
      84             :  * Generate a random floating-point value using caller-supplied state.
      85             :  * Values are uniformly distributed over the interval [0.0, 1.0).
      86             :  */
      87             : double
      88     1790180 : pg_erand48(unsigned short xseed[3])
      89             : {
      90     1790180 :     uint64      x = _dorand48(xseed);
      91             : 
      92     1790180 :     return ldexp((double) (x & UINT64CONST(0xFFFFFFFFFFFF)), -48);
      93             : }
      94             : 
      95             : /*
      96             :  * Generate a random non-negative integral value using internal state.
      97             :  * Values are uniformly distributed over the interval [0, 2^31).
      98             :  */
      99             : long
     100     3601976 : pg_lrand48(void)
     101             : {
     102     3601976 :     uint64      x = _dorand48(_rand48_seed);
     103             : 
     104     3601976 :     return (x >> 17) & UINT64CONST(0x7FFFFFFF);
     105             : }
     106             : 
     107             : /*
     108             :  * Generate a random signed integral value using caller-supplied state.
     109             :  * Values are uniformly distributed over the interval [-2^31, 2^31).
     110             :  */
     111             : long
     112        1436 : pg_jrand48(unsigned short xseed[3])
     113             : {
     114        1436 :     uint64      x = _dorand48(xseed);
     115             : 
     116        1436 :     return (int32) ((x >> 16) & UINT64CONST(0xFFFFFFFF));
     117             : }
     118             : 
     119             : /*
     120             :  * Initialize the internal state using the given seed.
     121             :  *
     122             :  * Per POSIX, this uses only 32 bits from "seed" even if "long" is wider.
     123             :  * Hence, the set of possible seed values is smaller than it could be.
     124             :  * Better practice is to use caller-supplied state and initialize it with
     125             :  * random bits obtained from a high-quality source of random bits.
     126             :  *
     127             :  * Note: POSIX specifies a function seed48() that allows all 48 bits
     128             :  * of the internal state to be set, but we don't currently support that.
     129             :  */
     130             : void
     131           0 : pg_srand48(long seed)
     132             : {
     133           0 :     _rand48_seed[0] = RAND48_SEED_0;
     134           0 :     _rand48_seed[1] = (unsigned short) seed;
     135           0 :     _rand48_seed[2] = (unsigned short) (seed >> 16);
     136           0 : }

Generated by: LCOV version 1.13