--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RandomParkMillerUsingFloat.st Tue Dec 16 23:39:51 2008 +0100
@@ -0,0 +1,142 @@
+"{ Package: 'stx:libbasic2' }"
+
+Object subclass:#RandomParkMillerUsingFloat
+ instanceVariableNames:'seed a m q r'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Magnitude-Numbers'
+!
+
+!RandomParkMillerUsingFloat class methodsFor:'documentation'!
+
+documentation
+"
+ Like RandomParkMiller, but using floats (instead of LargeInts).
+ This makes this one roughly 4 times faster.
+
+ Please read:
+ Standard reference by Park and Miller in
+ 'Random Number Generators: Good Ones Are Hard to Find',
+ Comm. ACM, 31:1192-1201, 1988.
+
+ [see also:]
+ Random - fast, but generates less quality random numbers
+ RandomTT800 - another random generator
+"
+!
+
+testing
+"
+
+ |r|
+
+ r := self new.
+ (1 to:10) collect:[:i | r next]
+
+ -> should be
+ #(
+ 0.1492432697
+ 0.3316330217
+ 0.7561964480
+ 0.3937015400
+ 0.9417831814
+ 0.5499291939
+ 0.6599625962
+ 0.9913545591
+ 0.6960744326
+ 0.9229878997
+ #)
+"
+! !
+
+!RandomParkMillerUsingFloat class methodsFor:'initialization'!
+
+initialize
+ PMa := 16807.
+ PMm := 2147483647. " magic constant = 16807 "
+ PMq := 127773. " magic constant = 2147483647 "
+ PMr := 2836. " quotient (m quo: a) = 44488 "
+ PMmu1 := 4.65661E-10 " remainder (m \\ a). = 2836 "
+! !
+
+!RandomParkMillerUsingFloat class methodsFor:'instance creation'!
+
+new
+ self initialize.
+ ^ super new initialize
+! !
+
+!RandomParkMillerUsingFloat methodsFor:'accessing-reading'!
+
+next
+ " This method generates random instances of Float in the interval 0.0 to 1.0 "
+
+ seed := self peekValue.
+ ^ seed / m
+!
+
+nextInteger
+ " This method generates random instances of Integer in the interval 0 to 16r7FFFFFFF. "
+
+ seed := self peekValue.
+ ^ seed
+
+ "
+ self new next
+ self new nextInteger
+ "
+! !
+
+!RandomParkMillerUsingFloat methodsFor:'initialization'!
+
+initialize
+ " Set a reasonable Park-Miller starting seed "
+
+ [
+ seed := (Time millisecondClockValue bitAnd: 16r3FFFFFFF) bitXor: self hash.
+ seed = 0
+ ] whileTrue: ["Try again if ever get a seed = 0"].
+
+ a := 16r000041A7 asFloat. " magic constant = 16807 "
+ m := 16r7FFFFFFF asFloat. " magic constant = 2147483647 "
+ q := (m quo: a) asFloat.
+ r := (m \\ a) asFloat.
+!
+
+seed:anInteger
+ seed := anInteger
+! !
+
+!RandomParkMillerUsingFloat methodsFor:'private'!
+
+peek
+ " This method answers the next random number that will be generated as a Float in the range [0..1).
+ It answers the same value for all successive message sends. "
+
+ ^ self peekValue / m
+!
+
+peekValue
+ "This method generates random instances of Integer in the interval
+ 0 to 16r7FFFFFFF. This method does NOT update the seed; repeated sends
+ answer the same value.
+ The algorithm is described in detail in 'Random Number Generators:
+ Good Ones Are Hard to Find' by Stephen K. Park and Keith W. Miller
+ (Comm. Asso. Comp. Mach., 31(10):1192--1201, 1988)."
+
+ |lo hi aLoRHi|
+
+ hi := (seed quo:q) asFloat.
+ lo := seed - (hi * q).
+ aLoRHi := (a * lo) - (r * hi).
+ (aLoRHi > 0) ifTrue:[ ^ aLoRHi ].
+ ^ aLoRHi + m
+! !
+
+!RandomParkMillerUsingFloat class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libbasic2/RandomParkMillerUsingFloat.st,v 1.1 2008-12-16 22:39:51 cg Exp $'
+! !
+
+RandomParkMillerUsingFloat initialize!