This is Random.m in view mode; [Download] [Up]
//
// 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.
//These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.