Sources/Random.cp

/*
    File:       Random.cp
 
    Contains:   TRandom is a stackbased utility class for random number generation.
                TRandom.cp contains the member function implementations for TRandom.
 
    Written by:     
 
    Copyright:  Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/18/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
// Include files
#ifndef _RANDOM_
#include "Random.h"
#endif
 
 
// _________________________________________________________________________________________________________ //
// TRandom class member function implementations
//  CONSTRUCTORS & DESTRUCTORS
#pragma segment Random
TRandom::TRandom(ERandType theType,
                 long theSeed,
                 unsigned short low,
                 unsigned short high)
// Default constructor, most of the parameters have default values defined in the
// header file (change if needed).
{
    if (theSeed == 1)                           // no seed value
        this->ShuffleSeed();                    // no first value, random value
    else
        this->SetSeedValue(theSeed);            // programmer defined seed  
 
    this->fLow = low;                           // define the range
    this->fHigh = high;
    this->fRange = high - low;
 
    Boolean fState = this->IRandom(theType);    // initialize the object
}
 
 
#pragma segment Random
TRandom::TRandom(const TRandom& other)
// copy constructor, creates clones of the TRandom class (deep copy).
{
    register int x;
 
    // fill in the needed fields with values from the referenced object
    this->fGenerator = other.fGenerator;
    this->fAlgorithm = other.fAlgorithm;
    this->fLow = other.fLow;
    this->fHigh = other.fHigh;
    this->fRange = other.fRange;
    this->fSeed = other.fSeed;
    this->fState = other.fState;
    this->fPrevNum = other.fPrevNum;
 
    for (x = 0; x < kSHUFFLETABLE; x++)         // copy the values from array
        this->fShuffleBuf[x] = other.fShuffleBuf[x];
}
 
 
#pragma segment Random
TRandom& TRandom::operator=(const TRandom& other)
// assignment operator, assign a TRandom class to another for quick cloning.
{
    register int x;
 
    // fill in the needed fields with values from the referenced object
    this->fGenerator = other.fGenerator;
    this->fAlgorithm = other.fAlgorithm;
    this->fLow = other.fLow;
    this->fHigh = other.fHigh;
    this->fRange = other.fRange;
    this->fSeed = other.fSeed;
    this->fState = other.fState;
    this->fPrevNum = other.fPrevNum;
 
    for (x = 0; x < kSHUFFLETABLE; x++)         // copy the values from array
        this->fShuffleBuf[x] = other.fShuffleBuf[x];
 
    return *this;
}
 
 
#pragma segment Random
TRandom::~TRandom()
// Virtual destructor, we are not doing anything inside this one just now, note 
// that virtual destructors should not be inlined.
{
}
 
 
//  INITIATION ROUTINES
#pragma segment Random
Boolean TRandom::IRandom(ERandType theType)
// We are using a special IRandom member function for initializing class fields to
// known values. This is called from both the constructor, and when we switch the
// internal random number algorithm.
{
    switch (theType)
    {
        case kMACOS:
            qd.randSeed = this->GetSeedValue();
            this->fGenerator = &TRandom::MacRandom;// quick init
            this->fAlgorithm = kMACOS;
            break;
        case kSHUFFLE:
            qd.randSeed = this->GetSeedValue();
            this->fGenerator = &TRandom::ShuffleRandom;
            this->fAlgorithm = kSHUFFLE;
            this->InitShuffleRandom();
            break;
        case kPM:
            this->fGenerator = &TRandom::ParkMiller;
            this->fAlgorithm = kPM;
            break;
        default:
            ASSERT(false, "\pProblems setting the algorithm for the random generator");
            return false;                       // should never get here...
    };
    return true;
}
 
 
//  RANDOM GENERATOR ALGORITHMS/MEMBER FUNCTIONS
#pragma segment Random
unsigned short TRandom::MacRandom()
// Macintosh Toolbox random number generator.
{
    register unsigned short temp;
 
    temp =
          short(::Random());                    // scale to  0 - 65536
    return (((temp * this->fRange) / k16BIT) + this->fLow);
}
 
 
 
 
#pragma segment Random
unsigned short TRandom::ShuffleRandom()
// Shuffle Random algorithm, uses an internal table for shuffling values for more
// random distribution
{
    register unsigned short index;
 
    index = (this->fPrevNum * kSHUFFLETABLE) / k16BIT;
    this->fPrevNum = this->fShuffleBuf[index];  // get random number from table
    this->fShuffleBuf[index] = Random();        // new random table entry
 
    return (((this->fPrevNum * this->fRange) / k16BIT) + this->fLow);
}
 
 
#pragma segment Random
TRandom& TRandom::InitShuffleRandom()
// Used to initialize the Shuffle random algorithm
{
    register short i;
 
    for (i = 0; i < kSHUFFLETABLE; i++)
        Random();                               // shuffle the random generator
    for (i = 0; i < kSHUFFLETABLE; i++)
        this->fShuffleBuf[i] = Random();        // fill the buffer
 
    this->fPrevNum = Random();                  // get first 'later' value
    return *this;
}
 
 
#pragma segment Random
unsigned short TRandom::ParkMiller()
// CACM Oct 1988 Park& Miller algorithm.
{
    unsigned short high,
     low;
    register unsigned short temp;
 
    high =
          short(this-> fSeed/ kPM3);
    low =
         short(this-> fSeed% kPM3);
    temp = (kPM2 * low) - (kPM1 * high);
 
    if (temp > 0)
        this->fSeed = temp;
    else
        this->fSeed = temp + kACM_MAX;
 
    return (((temp * this->fRange) / k16BIT) + this->fLow);
}
 
 
#pragma segment Random
unsigned short TRandom::Next()
// Iterate to next value.
{
    return (this->*fGenerator)();
}
 
 
#pragma segment Random
TRandom& TRandom::ShuffleSeed()
// Shuffle the current seed.
{
    this->fSeed = TickCount();
    return *this;
}
 
 
// GET/SET FUNCTIONS
#pragma segment Random
TRandom& TRandom::SetRandomGenerator(TRandom::ERandType theType)
// Select the random generator algorithm.
{
    this->IRandom(theType);
    return *this;
}
 
 
#pragma segment Random
long TRandom::GetSeedValue() const
// Return current seed value.
{
    return this->fSeed;
}
 
 
#pragma segment Random
TRandom& TRandom::SetSeedValue(const long theSeed)
// Set current seed value
{
    this->fSeed = theSeed;
    qd.randSeed = theSeed;
    return *this;
}
 
 
#pragma segment Random
TRandom::ERandType TRandom::GetAlgorithmType() const
// Return algorithm type.
{
    return this->fAlgorithm;
}
 
 
// _________________________________________________________________________________________________________ //
 
/*  Change History (most recent last):
  No        Init.   Date        Comment
  1         khs     6/2/92      New file
  2         khs     1/7/93      Cleanup
*/