Files
dvdisaster/random.c
2009-11-21 16:29:02 +09:00

151 lines
4.5 KiB
C

/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* This is derived from the Berkeley source:
* @(#)random.c 5.5 (Berkeley) 7/6/88
* It was reworked for the GNU C Library by Roland McGrath.
* Rewritten to use reentrant functions by Ulrich Drepper, 1995.
*/
/*
* This is derived from glibc-2.1:
* glibc2.1/stdlib/random.c
* glibc2.1/stdlib/random_r.c
* Code was reworked and cut down to be a work-alike of the default
* settings of srandom() and random() by Carsten Gnörlich, 2004.
*
* Note that the original code is much more sophisticated than this one,
* so you will probably want to review the real thing if you are
* interested in the inner workings of the original glibc functions.
*
* There's nothing special about this code; it's simply here to
* provide consistency among systems with different random()
* implementations. E.g. it makes sure that dvdisaster produces
* the same "random" images on all supported platforms.
*
* Note that unlike in the real thing, you must call SRandom()
* before using Random() the first time.
*/
#include "dvdisaster.h"
/* Some hardcoded values from glibc's default setting. */
#define MY_DEG 31
#define MY_SEP 3
/*
* State information for the random number generator.
*/
static gint32 *fptr; /* Front pointer. */
static gint32 *rptr; /* Rear pointer. */
static gint32 state[MY_DEG]; /* Array of state values. */
static gint32 *end_ptr; /* Pointer behind state table. */
/* Initialize the random number generator based on the given seed
* via a linear congruential generator.
* Then, the pointers are set to known locations that are exactly
* MY_SEP places apart.
* Lastly, it cycles the state information a given number of times
* to get rid of any initial dependencies introduced by the L.C.R.N.G.
*/
void SRandom(gint32 seed)
{ gint32 i;
gint32 word;
/* We must make sure the seed is not 0.
* Take arbitrarily 1 in this case. */
if (!seed) seed = 1;
/* This does: state[i] = (16807 * state[i - 1]) % 2147483647;
but avoids overflowing 31 bits. */
state[0] = word = seed;
for (i=1; i < MY_DEG; i++)
{ gint32 hi = word / 127773;
gint32 lo = word % 127773;
word = 16807 * lo - 2836 * hi;
if (word < 0) word += 2147483647;
state[i] = word;
}
/* Now prepare the pointers and cycle the state info 10 times around */
fptr = state + MY_SEP;
rptr = state;
end_ptr = state + MY_DEG;
for(i=10*MY_DEG; i; i--)
Random();
}
/* Deliver the next pseudo-random number in the current series.
* This uses only the trinomial branch of the original code,
* which is supposed to give the best results.
* The basic operation is to add the number at the rear pointer into
* the one at the front pointer. Then both pointers are advanced to the next
* location cyclically in the table. The value returned is the sum generated,
* reduced to 31 bits by throwing away the "least random" low bit.
* Note: The code takes advantage of the fact that both the front and
* rear pointers can't wrap on the same call by not testing the rear
* pointer if the front one has wrapped. Returns a 31-bit random number.
*/
gint32 Random(void)
{ gint32 val,result;
val = *fptr += *rptr;
/* Chucking least random bit. */
result = (val >> 1) & 0x7fffffff;
++fptr;
if(fptr >= end_ptr)
{ fptr = state;
++rptr;
}
else
{ ++rptr;
if(rptr >= end_ptr)
rptr = state;
}
return result;
}
/* Create a 32-bit random value from two sequential 31-bit values.
* Note that this is all simple stuff to produce a sequence of "different"
* numbers; it's not meant to deliver cryptographically strong random
* sequences.
*/
guint32 Random32(void)
{ guint32 value;
value = (Random() & 0xffff);
value <<= 16;
value |= (Random() & 0xffff);
return value;
}