|
|
#include "pch.hxx"
#include "randpeak.hxx"
/////////////////////////////////////////////////////////////////////////////
// //
// randpeak.c -- Functions to provide 32-bit random numbers, including //
// a linear distribution (Random32 and RandomInRange), //
// and a peaked distribution (RandomPeaked). //
// //
// Assumptions: ULONG is 32-bit unsigned data type, and //
// BOOL is an integral boolean type. //
// //
// If MULTITHREADED is defined, critical //
// section primitives must be defined and //
// supported. //
// //
// Two's complement wraparound (mod 2^32) //
// occurs on addition and multiplication //
// where result is greater than (2^32-1) //
// //
// Author: Tom McGuire (tommcg), 03/29/94 //
// //
// (C) Copyright 1994, Microsoft Corporation //
// //
/////////////////////////////////////////////////////////////////////////////
#define MULTIPLIER ((ULONG) 1664525 ) // From Knuth. Guarantees 2^32 non-
// repeating values.
ULONG ulInternalSeed; ULONG ulInternalAdder;
#ifdef MULTITHREADED
CRITICAL_SECTION ulInternalSeedCritSect; BOOL bInternalSeedCritSectInitialized; #endif
ULONG BitReverse32( ULONG ulNumber ) {
ULONG ulNewValue = 0; ULONG ulReadMask = 0x00000001; ULONG ulWriteBit = 0x80000000;
do { if ( ulNumber & ulReadMask ) ulNewValue |= ulWriteBit; ulReadMask <<= 1; ulWriteBit >>= 1; } while ( ulWriteBit );
return ulNewValue; }
void SeedRandom32( ULONG ulSeed ) {
//
// Assume this is called from a single thread only before any calls
// to Random32(), RandomInRange(), or RandomPeaked().
//
#ifdef MULTITHREADED
if ( ! bInternalSeedCritSectInitialized ) { InitializeCriticalSection( &ulInternalSeedCritSect ); bInternalSeedCritSectInitialized = TRUE; } #endif
ulInternalSeed = ulSeed; ulInternalAdder = ((( ulSeed ^ 0xFFFFFFFF ) | 0x00000001 ) & 0x7FFFFFFF );
}
ULONG Random32( void ) {
ULONG ulRand;
#ifdef MULTITHREADED
EnterCriticalSection( &ulInternalSeedCritSect ); #endif
ulRand = ( ulInternalSeed * MULTIPLIER ) + ulInternalAdder; ulInternalSeed = ulRand;
#ifdef MULTITHREADED
LeaveCriticalSection( &ulInternalSeedCritSect ); #endif
return BitReverse32( ulRand ); }
ULONG RandomInRange( ULONG ulMinInclusive, ULONG ulMaxInclusive ) {
ULONG ulRange = ( ulMaxInclusive - ulMinInclusive + 1 ); ULONG ulRand = Random32();
if ( ulRange ) ulRand %= ulRange;
return ( ulRand + ulMinInclusive ); }
ULONG RandomPeaked( ULONG ulMaxInclusive, ULONG ulPeakFrequency, ULONG ulPeakWidth, ULONG ulPeakDensity, ULONG ulPeakDecay ) {
ULONG ulWhichPeak, ulPeakValue, ulRange, ulHigh, ulLow;
ulWhichPeak = ( ulMaxInclusive / ulPeakFrequency );
do { ulWhichPeak = RandomInRange( 0, ulWhichPeak ); } while ( ulPeakDecay-- );
ulPeakValue = ulWhichPeak * ulPeakFrequency;
ulRange = ( ulPeakFrequency * ( ulPeakDensity + 1 )) / ( ulPeakDensity + 2 );
while ( ulPeakDensity-- ) ulRange = RandomInRange( ulPeakWidth / 2, ulRange );
ulLow = ( ulPeakValue > ulRange ) ? ( ulPeakValue - ulRange ) : 0; ulHigh = ( ulPeakValue + ulRange );
if ( ulHigh > ulMaxInclusive ) ulHigh = ulMaxInclusive;
ulPeakValue = RandomInRange( ulLow, ulHigh );
return ulPeakValue;
}
/////////////////////////////////////////////////////////////////////////////
// //
// | Peaked Distribution | //
// |_ | //
// | \ | //
// | \ _ | //
// | \ / \ _ | //
// | \ / \ / \ _ | //
// | \ / \ / \ / \ _| //
// | \_____/ \________/ \__ __/ \____________/ | //
// |_______________________________________________________________| //
// 0 P 2P nP Max //
// //
// The center of each peak occurs at ulPeakFreq intervals starting //
// from zero, and the tops of the peaks are linear-distributed across //
// ulPeakWidth (ie, +/- ulPeakWidth/2). ulPeakDensity controls the //
// slope of the distribution off each peak with higher numbers causing //
// steeper slopes (and hence wider, lower valleys). ulPeakDecay //
// controls the declining peak-to-peak slope with higher numbers //
// causing higher peaks near zero and lower peaks toward ulMax. //
// Note that ulPeakDensity and ulPeakDecay are computationally //
// expensive with higher values (they represent internal iteration //
// counts), so moderate numbers such as 3-5 for ulPeakDensity and //
// 1-2 for ulPeakDecay are recommended. //
// //
/////////////////////////////////////////////////////////////////////////////
|