171 lines
6.3 KiB
C++
171 lines
6.3 KiB
C++
#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. //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|