#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. // // // /////////////////////////////////////////////////////////////////////////////