This is Random.m in view mode; [Download] [Up]
// // Random // // Copyright (C) 1992 Contemporary Design Studios. All rights reserved. // #import "Random.h" #import <math.h> #import <stdlib.h> #import <stdio.h> @implementation Random // // version // + (int)version { return 3; // Version 3 = Release 2.0. } // // initEngineClass: // - initEngineClass:aClass { return [self initEngineInstance:[[aClass alloc] init]]; } // // initEngineInstance: // // DESIGNATED INITIALIZER // - initEngineInstance:anObject { [super init]; if(![anObject isKindOf:[RandomEngine class]]) { // // Can't do that! // } engine = anObject; engineClass = [engine class]; unit = [engineClass unit]; bitbuffer = (uchar *)malloc(unit); bytebuffer = (uchar *)malloc(unit); curbit = 0; curbyte = 0; [engine makeRandom:bitbuffer]; // Make some bits. [engine makeRandom:bytebuffer]; // Make some bytes. return self; } // // rand // - (ulong) rand { ulong temp = 0; char *ptr = (char *)(&temp); ulong i; for(i = 0; i < 4; i++) { if(curbyte == unit) { // i.e., bytebuffer empty. [engine makeRandom:bytebuffer]; curbyte = 0; } ptr[i] = bytebuffer[curbyte]; curbyte++; } return temp; } // // randMax: // // This isn't the most conservative algorithm possible. One could rotate bits and/or // bytes to try to come up with a value in range. However, the added complexity could // bog down the code even further. Therefore, until somebody proves that being more // conservative is useful, or a really clever, yet clear, algorithm presents itself, // this will suffice. Execution should be reasonably fast, and usage of random bits // and bytes should be reasonably light with this algorithm. // - (ulong) randMax:(ulong)max { ulong ret = 0; ulong *ptr = &ret; int i; if(max == 0) { ret = 0; } else if(max == 1) { // One bit needed. if(curbit == (unit * 8)) { [engine makeRandom:bitbuffer]; curbit = 0; } ret = bitbuffer[curbit / 8] & (0x01 << (curbit % 8)); curbit++; } else if(max <= 0x000000ff) { // One byte needed. do { if(curbyte == unit) { [engine makeRandom:bytebuffer]; curbyte = 0; } ret = bytebuffer[curbyte]; curbyte++; } while (ret > max); } else if(max <= 0x0000ffff) { // Two bytes needed. do { for(i = 0; i < 2; i++) { if(curbyte == unit) { [engine makeRandom:bytebuffer]; curbyte = 0; } ptr[i + 2] = bytebuffer[curbyte]; curbyte++; } } while (ret > max); } else if(max <= 0x00ffffff) { // Three bytes needed. do { for(i = 0; i < 3; i++) { if(curbyte == unit) { [engine makeRandom:bytebuffer]; curbyte = 0; } ptr[i + 1] = bytebuffer[curbyte]; curbyte++; } } while (ret > max); } else { // Four bytes needed. do { for(i = 0; i < 4; i++) { if(curbyte == unit) { [engine makeRandom:bytebuffer]; curbyte = 0; } ptr[i] = bytebuffer[curbyte]; curbyte++; } } while (ret > max); } return ret; } // // randMin:max: // - (ulong)randMin:(ulong)min max:(ulong)max { return min + [self randMax:(max - min)]; } // // percent // // The information in the following exerpt was used to determine the // construction of a double-precision number with a value between 0.0 and // 1.0. It turns out to be easiest to construct one with a mantissa of: // // 1.rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rrrrrrrrrr rr // // Where "r" stands for a random bit, and where the exponent is 0, i.e. // E is 1023, or 01111111111. Of course, the sign bit is 0. So, the // resulting number is: // // 00111111 1111rrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr rrrrrrrr // // Nicely enough, there is only 1 byte which is a mix of constant and // random bits. So, the trick is to generate 7 bytes of random data, and // then to overlay the constant 1111 into the high-order nibble of the // 2nd byte. Then, the first byte is just the constant 00111111. // // Of course, this is technically platform dependant, which is a no-no, // but I suppose if we move it to another machine, there may be a function // to convert from XDR format (which this is) to the local format (one can // hope), which would save us. // // -------------------------------- EXERPT -------------------------------- // // Network Working Group Sun Microsystems, Inc. // Request for Comments: 1014 June 1987 // // // XDR: External Data Representation Standard // // ------------------------------------------------------------------------ // // 3.7 Double-precision Floating-point // // The standard defines the encoding for the double-precision floating- // point data type "double" (64 bits or 8 bytes). The encoding used is // the IEEE standard for normalized double-precision floating-point // numbers [3]. The standard encodes the following three fields, which // describe the double-precision floating-point number: // // S: The sign of the number. Values 0 and 1 represent positive and // negative, respectively. One bit. // // E: The exponent of the number, base 2. 11 bits are devoted to // this field. The exponent is biased by 1023. // // F: The fractional part of the number's mantissa, base 2. 52 bits // are devoted to this field. // // Therefore, the floating-point number is described by: // // (-1)**S * 2**(E-Bias) * 1.F // // It is declared as follows: // // double identifier; // // +------+------+------+------+------+------+------+------+ // |byte 0|byte 1|byte 2|byte 3|byte 4|byte 5|byte 6|byte 7| // S| E | F | // +------+------+------+------+------+------+------+------+ // 1|<--11-->|<-----------------52 bits------------------->| // <-----------------------64 bits-------------------------> // DOUBLE-PRECISION FLOATING-POINT // // Just as the most and least significant bytes of a number are 0 and 3, // the most and least significant bits of a double-precision floating- // point number are 0 and 63. The beginning bit (and most significant // bit) offsets of S, E , and F are 0, 1, and 12, respectively. Note // that these numbers refer to the mathematical positions of the bits, // and NOT to their actual physical locations (which vary from medium to // medium). // // The IEEE specifications should be consulted concerning the encoding // for signed zero, signed infinity (overflow), and denormalized numbers // (underflow) [3]. According to IEEE specifications, the "NaN" (not a // number) is system dependent and should not be used externally. // // ------------------------------------------------------------------------ // // [3] "IEEE Standard for Binary Floating-Point Arithmetic", ANSI/IEEE // Standard 754-1985, Institute of Electrical and Electronics // Engineers, August 1985. // // ------------------------------------------------------------------------ // - (double)percent { double temp; int i; for(i = 1; i < 8; i++) { if(curbyte == unit) { // i.e., bytebuffer empty. [engine makeRandom:bytebuffer]; curbyte = 0; } ((uchar *)(&temp))[i] = bytebuffer[curbyte]; curbyte++; } ((ulong *)(&temp))[0] &= ((ulong)0x000fffff); ((ulong *)(&temp))[0] |= ((ulong)0x3ff00000); return (temp - 1.0); } // // bool // - (BOOL)bool { BOOL temp; if(curbit == (unit * 8)) { // i.e., bitbuffer empty. [engine makeRandom:bitbuffer]; curbit = 0; } temp = bitbuffer[curbit / 8] & (0x01 << (curbit % 8)); curbit++; return (temp != 0); } // // randFunc: // - (double)randFunc:(ddfunc)func { return (*func)([self percent]); } // // read: // - read:(NXTypedStream *)stream { [super read:stream]; // // Read in the engine: // NXReadTypes(stream, "@", &engine); // // Set related instance variables: // engineClass = [engine class]; unit = [engineClass unit]; bitbuffer = (uchar *)malloc(unit); bytebuffer = (uchar *)malloc(unit); curbit = 0; curbyte = 0; // // Read in the buffers: // [engine makeRandom:bitbuffer]; // Make some bits. [engine makeRandom:bytebuffer]; // Make some bytes. return self; } // // write: // - write:(NXTypedStream *)stream { [super write:stream]; // // Write out the engine: // NXWriteTypes(stream, "@", &engine); // // Write out the buffers: // 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.