home *** CD-ROM | disk | FTP | other *** search
- //
- // Random
- //
- // <<See the file Random.h for more information>>.
- //
- // Version 1.1, 1992 Feb 27
- //
- // Written by Gregor Purdy
- // gregor@umich.edu
- //
- // See the README file included for information
- // and distribution and usage rights.
- //
-
-
- #import <sys/time.h>
- #import <math.h>
- #import "Random.h"
-
-
- #define RAND_DEBUG
-
-
- @implementation Random
-
-
- + (int)version
- {
- return 2; // Was 0 last release, but should have been 1.
- }
-
-
- - init
- {
- [super init]; // Make a new instance using superclass' method
- [self newSeeds]; // Get a new seed for ourselves
-
- iset = 0; // No saved gaussian yet.
- gset = 0.0;
-
- gscale = 1.0;
- gorigin = 0.0;
-
- return self;
- }
-
-
- - initSeeds:(int)s1 :(int)s2 :(int)s3
- {
- [super init];
- [self setSeeds:s1 :s2 :s3];
-
- return self;
- }
-
-
- - newSeeds
- {
- struct timeval theTime; // gettimeofday return structure
-
- gettimeofday(&theTime,0); // Get the time of day in seconds and microseconds
- h1 = theTime.tv_usec; // Set seed 1 by microseconds past second
- gettimeofday(&theTime,0); // Get the time of day in seconds and microseconds
- h2 = theTime.tv_usec; // Set seed 2 by microseconds past second
- gettimeofday(&theTime,0); // Get the time of day in seconds and microseconds
- h3 = theTime.tv_usec; // Set seed 3 by microseconds past second
-
- return self;
- }
-
-
- - setSeeds:(int) s1 :(int) s2 :(int) s3
- {
- h1 = s1; // Set the seeds to the values given
- h2 = s2;
- h3 = s3;
-
- return self;
- }
-
-
- - getSeeds:(int *)s1 :(int *)s2 :(int *)s3
- {
- if((s1 == NULL) || (s2 == NULL) || (s3 == NULL))
- return nil;
-
- *s1 = h1;
- *s2 = h2;
- *s3 = h3;
-
- return self;
- }
-
-
- //
- // See the Source article for the explanations of these constants
- //
- #define M1 32771
- #define M2 32779
- #define M3 32783
- #define F1 179
- #define F2 183
- #define F3 182
-
- #define MAXNUM 32767
- #define RANGE 32768
-
- - (int) rand
- {
- h1 = (F1 * h1) % M1; // Update the sections
- h2 = (F2 * h2) % M2;
- h3 = (F2 * h3) % M3;
-
- if ((h1 > MAXNUM) || (h2 > MAXNUM) || (h3 > MAXNUM)) // If a section is out of range,
- return [self rand]; // return next result
- else // Otherwise,
- return (h1 + h2 + h3) % RANGE; // Return this result
- }
-
-
- - (int) randMax:(int)max
- {
- if(max <= 0)
- return 0;
- else
- return (int)((float)[self rand] / (float)RANGE * (float)(max + 1));
- }
-
-
- - (int)randMin:(int)min max:(int)max
- {
- return min + [self randMax:(max - min)];
- }
-
-
- - (double)percent
- {
- return ((double)[self rand] / (double)RANGE);
- }
-
-
- - (BOOL)bool
- {
- return ([self randMax:1]);
- }
-
-
- - (int)rollDie:(int) numSides
- {
- return [self randMax:(numSides - 1)] + 1;
- }
-
-
- - (int)roll:(int) numRolls die:(int) numSides
- {
- int temp = 0;
- int loop;
-
- for (loop = 1 ; loop <= numRolls ; loop++ )
- temp += [self rollDie:numSides];
-
- return temp;
- }
-
-
- - (int) rollBest:(int)numWanted of:(int)numRolls die:(int)numSides
- {
- int temp[numRolls]; // Array of rolls
- int loop1; // First loop control variable
- int loop2; // Second loop control variable
- int highest; // Index of highest found roll
- int accumulator = 0; // Accumulates total best roll
-
- for (loop1 = 1 ; loop1 <= numRolls ; loop1++) // Fill an array with rolls
- temp[loop1] = [self rollDie:numSides];
-
- for (loop1 = 1 ; loop1 <= numWanted; loop1++) {
- highest = 1; // Start off as if first is highest
- for (loop2 = 2 ; loop2 <= numRolls ; loop2++) // Scan array for higher rolls
- if (temp[loop2] > temp[highest]) // If temp[loop2] is higher, then
- highest = loop2; // remember that fact
- accumulator += temp[highest]; // Add highest roll to accumulator
- temp[highest] = 0; // Clear highest roll so we don't find it again
- }
-
- return accumulator; // Return what we found
- }
-
-
- - (double)randFunc:(ddfunc)func
- {
- return (*func)([self percent]);
- }
-
-
- - (double)gScale
- {
- return gscale;
- }
-
-
- - setGScale:(double)aScale
- {
- gscale = aScale;
-
- return self;
- }
-
-
- - (double)gOrigin
- {
- return gorigin;
- }
-
-
- - setGOrigin:(double)anOrigin
- {
- gorigin = anOrigin;
-
- return self;
- }
-
-
- - (double)gaussian
- {
- double fac, r, v1, v2, temp;
-
- if(iset == 0) { // If none stored, calculate a pair.
- r = 0.0;
-
- while((r >= 1.0) || (r == 0.0)) { // Find a pair which are inside unit circle.
- v1 = 2.0 * [self percent] - 1.0;
- v2 = 2.0 * [self percent] - 1.0;
- r = (v1 * v1) + (v2 * v2);
- }
-
- fac = sqrt(-2.0 * log(r) / r); // Do Box-Muller transformation.
- gset = v1 * fac;
- iset = 1;
-
- temp = v2 * fac; // Return one of the pair.
- }
- else { // Otherwise return stored one.
- iset = 0;
- temp = gset;
- }
-
- return ((temp * gscale) + gorigin); // Modify the variable.
- }
-
-
- - read:(NXTypedStream *)stream
- {
- [super read:stream];
-
- NXReadTypes(stream, "iiiiddd", &h1, &h2, &h3, &iset, &gset, &gscale, &gorigin);
-
- return self;
- }
-
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
-
- NXWriteTypes(stream, "iiiiddd", &h1, &h2, &h3, &iset, &gset, &gscale, &gorigin);
-
- return self;
- }
-
-
- @end
-
-
- //
- // End of file.
- //