mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-01 08:07:10 -04:00
5ac886855d
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6437 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
568 lines
12 KiB
C
Executable File
568 lines
12 KiB
C
Executable File
/* RAND.C - Random number generation module. */
|
|
|
|
/* Copyright (c) 1995-2012 by Radford M. Neal.
|
|
*
|
|
* Permission is granted for anyone to copy, use, modify, and distribute
|
|
* these programs and accompanying documents for any purpose, provided
|
|
* this copyright notice is retained and prominently displayed, and note
|
|
* is made of any changes made to these programs. These programs and
|
|
* documents are distributed without any warranty, express or implied.
|
|
* As the programs were written for research purposes only, they have not
|
|
* been tested to the degree that would be advisable in any important
|
|
* application. All use of these programs is entirely at the user's own
|
|
* risk.
|
|
*/
|
|
|
|
/* Random generation routines at the end of this file are taken from the
|
|
GNU C library, see the copyright notice there. */
|
|
|
|
|
|
/* NOTE: See rand.html for documentation on these procedures. */
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "rand.h"
|
|
|
|
|
|
static long int this_nrand48 (unsigned short int [3]);
|
|
/* Local version of nrand48 */
|
|
|
|
|
|
/* This module uses the 'this_nrand48' pseudo-random number generator from the
|
|
GNU C library, included below, but renamed to 'this_nrand48'. The
|
|
output of this generator is combined with a file of real random numbers.
|
|
|
|
Many of the methods used in this module may be found in the following
|
|
reference:
|
|
|
|
Devroye, L. (1986) Non-Uniform Random Variate Generation,
|
|
New York: Springer-Verlag.
|
|
|
|
The methods used here are not necessarily the fastest available. They're
|
|
selected to be reasonably fast while also being easy to write.
|
|
*/
|
|
|
|
|
|
/* CONSTANT PI. Defined here if not in <math.h>. */
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
|
|
/* TABLES OF REAL RANDOM NUMBERS. A file of 100000 real random numbers
|
|
(NOT pseudo-random) is used in conjunction with pseudo-random numbers
|
|
for extra insurance. These are employed in the form of five tables
|
|
of 5000 32-bit integers.
|
|
|
|
The file must be located at the path given by RAND_FILE, which should
|
|
be defined on the "cc" command line. */
|
|
|
|
#define Table_size 5000 /* Number of words in each table */
|
|
|
|
static int rn[N_tables][Table_size]; /* Random number tables */
|
|
|
|
|
|
/* STATE OF RANDOM NUMBER GENERATOR. */
|
|
|
|
static int initialized = 0; /* Has module been initialized? */
|
|
|
|
static rand_state state0; /* Default state structure */
|
|
|
|
static rand_state *state; /* Pointer to current state */
|
|
|
|
|
|
/* INITIALIZE MODULE. Sets things up using the default state structure,
|
|
set as if rand_seed had been called with a seed of one. */
|
|
|
|
static void initialize (void)
|
|
{
|
|
int i, j, k, w;
|
|
char b;
|
|
FILE *f;
|
|
|
|
if (!initialized)
|
|
{
|
|
f = fopen(RAND_FILE,"rb");
|
|
|
|
if (f==NULL)
|
|
{ fprintf(stderr,"Can't open file of random numbers (%s)\n",RAND_FILE);
|
|
exit(1);
|
|
}
|
|
|
|
for (i = 0; i<N_tables; i++)
|
|
{ for (j = 0; j<Table_size; j++)
|
|
{ w = 0;
|
|
for (k = 0; k<4; k++)
|
|
{ if (fread(&b,1,1,f)!=1)
|
|
{ fprintf(stderr,"Error reading file of random numbers (%s)\n",
|
|
RAND_FILE);
|
|
exit(1);
|
|
}
|
|
w = (w<<8) | (b&0xff);
|
|
}
|
|
rn[i][j] = w;
|
|
}
|
|
}
|
|
|
|
state = &state0;
|
|
|
|
initialized = 1;
|
|
|
|
rand_seed(1);
|
|
}
|
|
}
|
|
|
|
|
|
/* SET CURRENT STATE ACCORDING TO SEED. */
|
|
|
|
void rand_seed
|
|
( int seed
|
|
)
|
|
{
|
|
int j;
|
|
|
|
if (!initialized) initialize();
|
|
|
|
state->seed = seed;
|
|
|
|
state->state48[0] = seed>>16;
|
|
state->state48[1] = seed&0xffff;
|
|
state->state48[2] = rn[0][(seed&0x7fffffff)%Table_size];
|
|
|
|
for (j = 0; j<N_tables; j++)
|
|
{ state->ptr[j] = seed%Table_size;
|
|
seed /= Table_size;
|
|
}
|
|
}
|
|
|
|
|
|
/* SET STATE STRUCTURE TO USE. */
|
|
|
|
void rand_use_state
|
|
( rand_state *st
|
|
)
|
|
{
|
|
if (!initialized) initialize();
|
|
|
|
state = st;
|
|
}
|
|
|
|
|
|
/* RETURN POINTER TO CURRENT STATE. */
|
|
|
|
rand_state *rand_get_state (void)
|
|
{
|
|
if (!initialized) initialize();
|
|
|
|
return state;
|
|
}
|
|
|
|
|
|
/* GENERATE RANDOM 31-BIT INTEGER. Not really meant for use outside this
|
|
module. */
|
|
|
|
int rand_word(void)
|
|
{
|
|
int v;
|
|
int j;
|
|
|
|
if (!initialized) initialize();
|
|
|
|
v = this_nrand48(state->state48);
|
|
|
|
for (j = 0; j<N_tables; j++)
|
|
{ v ^= rn[j][state->ptr[j]];
|
|
}
|
|
|
|
for (j = 0; j<N_tables && state->ptr[j]==Table_size-1; j++)
|
|
{ state->ptr[j] = 0;
|
|
}
|
|
|
|
if (j<N_tables)
|
|
{ state->ptr[j] += 1;
|
|
}
|
|
|
|
return v & 0x7fffffff;
|
|
}
|
|
|
|
|
|
/* GENERATE UNIFORMLY FROM [0,1). */
|
|
|
|
double rand_uniform (void)
|
|
{
|
|
return (double)rand_word() / (1.0+(double)0x7fffffff);
|
|
}
|
|
|
|
|
|
/* GENERATE UNIFORMLY FORM (0,1). */
|
|
|
|
double rand_uniopen (void)
|
|
{
|
|
return (0.5+(double)rand_word()) / (1.0+(double)0x7fffffff);
|
|
}
|
|
|
|
|
|
/* GENERATE RANDOM INTEGER FROM 0, 1, ..., (n-1). */
|
|
|
|
int rand_int
|
|
( int n
|
|
)
|
|
{
|
|
return (int) (n * rand_uniform());
|
|
}
|
|
|
|
|
|
/* GENERATE INTEGER FROM 0, 1, ..., (n-1), WITH GIVEN DISTRIBUTION. */
|
|
|
|
int rand_pickd
|
|
( double *p,
|
|
int n
|
|
)
|
|
{
|
|
double t, r;
|
|
int i;
|
|
|
|
t = 0;
|
|
for (i = 0; i<n; i++)
|
|
{ if (p[i]<0) abort();
|
|
t += p[i];
|
|
}
|
|
|
|
if (t<=0) abort();
|
|
|
|
r = t * rand_uniform();
|
|
|
|
for (i = 0; i<n; i++)
|
|
{ r -= p[i];
|
|
if (r<0) return i;
|
|
}
|
|
|
|
/* Return value with non-zero probability if we get here due to roundoff. */
|
|
|
|
for (i = 0; i<n; i++)
|
|
{ if (p[i]>0) return i;
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
|
|
/* SAME PROCEDURE AS ABOVE, BUT WITH FLOAT ARGUMENT. */
|
|
|
|
int rand_pickf
|
|
( float *p,
|
|
int n
|
|
)
|
|
{
|
|
double t, r;
|
|
int i;
|
|
|
|
t = 0;
|
|
for (i = 0; i<n; i++)
|
|
{ if (p[i]<=0) abort();
|
|
t += p[i];
|
|
}
|
|
|
|
if (t<=0) abort();
|
|
|
|
r = t * rand_uniform();
|
|
|
|
for (i = 0; i<n; i++)
|
|
{ r -= p[i];
|
|
if (r<0) return i;
|
|
}
|
|
|
|
/* Return value with non-zero probability if we get here due to roundoff. */
|
|
|
|
for (i = 0; i<n; i++)
|
|
{ if (p[i]>0) return i;
|
|
}
|
|
|
|
abort();
|
|
}
|
|
|
|
|
|
/* GENERATE RANDOM PERMUTATION OF INTEGERS FROM 1 TO N. */
|
|
|
|
void rand_permutation
|
|
( int *perm, /* Place to store permutation */
|
|
int n /* Number of integers to permute */
|
|
)
|
|
{
|
|
int i, j, t;
|
|
|
|
for (i = 0; i<n; i++)
|
|
{ perm[i] = i+1;
|
|
}
|
|
|
|
for (i = 0; i<n; i++)
|
|
{ t = perm[i];
|
|
j = i + rand_int(n-i);
|
|
perm[i] = perm[j];
|
|
perm[j] = t;
|
|
}
|
|
}
|
|
|
|
|
|
/* POISSON GENERATOR. The method used is simple, but not very fast. See
|
|
Devroye, p. 503. Very large means are done using Gaussian approximation. */
|
|
|
|
int rand_poisson
|
|
( double lambda
|
|
)
|
|
{ int v;
|
|
if (lambda>10000)
|
|
{ v = (int) (lambda + rand_gaussian()*sqrt(lambda) + 0.5);
|
|
}
|
|
else
|
|
{ v = 0;
|
|
for (;;)
|
|
{ lambda -= rand_exp();
|
|
if (lambda<=0) break;
|
|
v += 1;
|
|
}
|
|
}
|
|
return v;
|
|
}
|
|
|
|
|
|
/* GAUSSIAN GENERATOR. Done by using the Box-Muller method, but only one
|
|
of the variates is retained (using both would require saving more state).
|
|
See Devroye, p. 235.
|
|
|
|
As written, should never deliver exactly zero, which may sometimes be
|
|
helpful. */
|
|
|
|
double rand_gaussian (void)
|
|
{
|
|
double a, b;
|
|
|
|
a = rand_uniform();
|
|
b = rand_uniopen();
|
|
|
|
return cos(2.0*M_PI*a) * sqrt(-2.0*log(b));
|
|
}
|
|
|
|
|
|
/* EXPONENTIAL GENERATOR. See Devroye, p. 29. Written so as to never
|
|
return exactly zero. */
|
|
|
|
double rand_exp (void)
|
|
{
|
|
return -log(rand_uniopen());
|
|
}
|
|
|
|
|
|
/* LOGISTIC GENERATOR. Just inverts the CDF. */
|
|
|
|
double rand_logistic (void)
|
|
{ double u;
|
|
u = rand_uniopen();
|
|
return log(u/(1-u));
|
|
}
|
|
|
|
|
|
/* CAUCHY GENERATOR. See Devroye, p. 29. */
|
|
|
|
double rand_cauchy (void)
|
|
{
|
|
return tan (M_PI * (rand_uniopen()-0.5));
|
|
}
|
|
|
|
|
|
/* GAMMA GENERATOR. Generates a positive real number, r, with density
|
|
proportional to r^(a-1) * exp(-r). See Devroye, p. 410 and p. 420.
|
|
Things are fiddled to avoid ever returning a value that is very near
|
|
zero. */
|
|
|
|
double rand_gamma
|
|
( double a
|
|
)
|
|
{
|
|
double b, c, X, Y, Z, U, V, W;
|
|
|
|
if (a<0.00001)
|
|
{ X = a;
|
|
}
|
|
|
|
else if (a<=1)
|
|
{
|
|
U = rand_uniopen();
|
|
X = rand_gamma(1+a) * pow(U,1/a);
|
|
}
|
|
|
|
else if (a<1.00001)
|
|
{ X = rand_exp();
|
|
}
|
|
|
|
else
|
|
{
|
|
b = a-1;
|
|
c = 3*a - 0.75;
|
|
|
|
for (;;)
|
|
{
|
|
U = rand_uniopen();
|
|
V = rand_uniopen();
|
|
|
|
W = U*(1-U);
|
|
Y = sqrt(c/W) * (U-0.5);
|
|
X = b+Y;
|
|
|
|
if (X>=0)
|
|
{
|
|
Z = 64*W*W*W*V*V;
|
|
|
|
if (Z <= 1 - 2*Y*Y/X || log(Z) <= 2 * (b*log(X/b) - Y)) break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return X<1e-30 && X<a ? (a<1e-30 ? a : 1e-30) : X;
|
|
}
|
|
|
|
|
|
/* BETA GENERATOR. Generates a real number, r, in (0,1), with density
|
|
proportional to r^(a-1) * (1-r)^(b-1). Things are fiddled to avoid
|
|
the end-points, and to make the procedure symmetric between a and b. */
|
|
|
|
double rand_beta
|
|
( double a,
|
|
double b
|
|
)
|
|
{
|
|
double x, y, r;
|
|
|
|
do
|
|
{ x = rand_gamma(a);
|
|
y = rand_gamma(b);
|
|
r = 1.0 + x/(x+y);
|
|
r = r - 1.0;
|
|
} while (r<=0.0 || r>=1.0);
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
/* ROUTINES FROM THE GNU C LIBRARY. These were modified to extract
|
|
only the routines used here, and to allow them to be included in
|
|
this module without any possible name conflict with other modules.
|
|
Inclusion here ensures that these routines are always available, and
|
|
operate in exactly the same way on all systems. The routines as copied
|
|
below are still easily useable by other programs by simply inserting
|
|
this source code into an appropriate source file.
|
|
|
|
The following is the copyright notice for these routines:
|
|
|
|
Copyright (C) 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307 USA.
|
|
|
|
The GNU Lesser General Public License is included with these source
|
|
files in the file LGPL. */
|
|
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <sys/types.h>
|
|
|
|
struct this_drand48_data
|
|
{
|
|
unsigned short int x[3]; /* Current state. */
|
|
unsigned short int old_x[3]; /* Old state. */
|
|
unsigned short int c; /* Additive const. in congruential formula. */
|
|
unsigned short int init; /* Flag for initializing. */
|
|
unsigned long long int a; /* Factor in congruential formula. */
|
|
};
|
|
|
|
/* Global state for non-reentrant functions. */
|
|
|
|
struct this_drand48_data libc_this_drand48_data;
|
|
|
|
static int this_nrand48_r (unsigned short int xsubi[3],
|
|
struct this_drand48_data *buffer,
|
|
long int *result);
|
|
|
|
/* Internal function to compute next state of the generator. */
|
|
|
|
static int this_drand48_iterate (unsigned short int xsubi[3],
|
|
struct this_drand48_data *buffer);
|
|
|
|
static long int this_nrand48 (xsubi)
|
|
unsigned short int xsubi[3];
|
|
{
|
|
long int result;
|
|
|
|
(void) this_nrand48_r (xsubi, &libc_this_drand48_data, &result);
|
|
|
|
return result;
|
|
}
|
|
|
|
static int this_nrand48_r (xsubi, buffer, result)
|
|
unsigned short int xsubi[3];
|
|
struct this_drand48_data *buffer;
|
|
long int *result;
|
|
{
|
|
/* Compute next state. */
|
|
if (this_drand48_iterate (xsubi, buffer) < 0)
|
|
return -1;
|
|
|
|
/* Store the result. */
|
|
if (sizeof (unsigned short int) == 2)
|
|
*result = xsubi[2] << 15 | xsubi[1] >> 1;
|
|
else
|
|
*result = xsubi[2] >> 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int this_drand48_iterate (xsubi, buffer)
|
|
unsigned short int xsubi[3];
|
|
struct this_drand48_data *buffer;
|
|
{
|
|
uint64_t X;
|
|
uint64_t result;
|
|
|
|
/* Initialize buffer, if not yet done. */
|
|
if (!buffer->init)
|
|
{
|
|
buffer->a = 0x5deece66dull;
|
|
buffer->c = 0xb;
|
|
buffer->init = 1;
|
|
}
|
|
|
|
/* Do the real work. We choose a data type which contains at least
|
|
48 bits. Because we compute the modulus it does not care how
|
|
many bits really are computed. */
|
|
|
|
X = (uint64_t) xsubi[2] << 32 | (uint32_t) xsubi[1] << 16 | xsubi[0];
|
|
|
|
result = X * buffer->a + buffer->c;
|
|
|
|
xsubi[0] = result & 0xffff;
|
|
xsubi[1] = (result >> 16) & 0xffff;
|
|
xsubi[2] = (result >> 32) & 0xffff;
|
|
|
|
return 0;
|
|
}
|