--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RandomGenerator.st Fri Mar 10 09:51:39 2006 +0100
@@ -0,0 +1,290 @@
+"{ Package: 'stx:libbasic2' }"
+
+Object subclass:#RandomGenerator
+ instanceVariableNames:''
+ classVariableNames:'RandFile'
+ poolDictionaries:''
+ category:'Magnitude-Numbers'
+!
+
+!RandomGenerator class methodsFor:'documentation'!
+
+documentation
+"
+ This is a Random number generator, which uses either a OS random number generator,
+ or a ST/X internal random number generator.
+
+ [author:]
+ Stefan Vogel
+
+ [see also:]
+ Random HashRandom Rc4Stream
+
+ [instance variables:]
+
+ [class variables:]
+ RandFile the FileStream we get random numbers from
+"
+! !
+
+!RandomGenerator class methodsFor:'initialization'!
+
+initialize
+ "want to be informed when returning from snapshot"
+
+ ObjectMemory addDependent:self.
+
+
+!
+
+openRandFile
+ "try to open a random device"
+
+ |randDevName|
+
+ RandFile isStream ifTrue:[
+ RandFile close.
+ ].
+
+ RandFile := false. "prevent retry"
+
+ randDevName := self randPath.
+ randDevName notNil ifTrue:[
+ randDevName := randDevName asFilename.
+ randDevName isReadable ifTrue:[
+ RandFile := randDevName readStream
+ ].
+ ].
+! !
+
+!RandomGenerator class methodsFor:'instance creation'!
+
+new
+ "return a new random number generator.
+ Try to get system random numbers from device (e.g. in LINUX).
+ If no system random nubers are available, fall back to
+ a cryptographic secure PRNG (part of the extra libcrypt package).
+ As last resort fallback to the cryptographic insecure linear builtin PRNG"
+
+ RandFile isNil ifTrue:[
+ self openRandFile.
+ ].
+ RandFile isStream ifTrue:[
+ ^ self basicNew.
+ ].
+ Rc4Cipher notNil ifTrue:[
+ ^ Rc4Cipher random
+ ].
+
+ ^ Random sharedGenerator
+!
+
+random
+ "alias for new - protocol compatibility with StreamCiphers"
+
+ ^ self new
+! !
+
+!RandomGenerator class methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+ "handle image restarts and flush any device resource handles"
+
+ RandFile notNil ifTrue:[
+ RandFile := nil.
+ self openRandFile.
+ ].
+
+
+! !
+
+!RandomGenerator class methodsFor:'queries'!
+
+randPath
+ "path to a file/device that is a source or random numbers"
+
+ OperatingSystem isUNIXlike ifTrue:[^ '/dev/urandom'].
+ ^ nil.
+! !
+
+!RandomGenerator methodsFor:'reading'!
+
+next
+ "return the next random number in the range 0..1"
+
+ ^ self nextInteger / 16r3fffffff asFloat
+
+ "
+ |r|
+ r := RandomGenerator new.
+ Transcript showCR:r next.
+ Transcript showCR:r next.
+ Transcript showCR:r next.
+ Transcript showCR:r next.
+ "
+
+ "Modified: / 11.11.1999 / 10:31:35 / stefan"
+!
+
+nextBetween:start and:stop
+ "return a random number between start and stop."
+
+ |rnd|
+
+ rnd := self next.
+ rnd := rnd * (stop - start) asFloat.
+ rnd := rnd + start asFloat.
+ ^ rnd
+
+ "
+ |r|
+ r := RandomGenerator new.
+ Transcript showCR:(r nextBetween:1 and:10).
+ Transcript showCR:(r nextBetween:1 and:10).
+ Transcript showCR:(r nextBetween:1 and:10).
+ Transcript showCR:(r nextBetween:1 and:10).
+ "
+
+ "Created: / 11.11.1999 / 10:27:56 / stefan"
+!
+
+nextBoolean
+ "return true or false by random"
+
+ ^ self nextByte <= 127
+
+ "
+ |r|
+ r := RandomGenerator new.
+ Transcript showCR:r nextBoolean.
+ Transcript showCR:r nextBoolean.
+ Transcript showCR:r nextBoolean.
+ Transcript showCR:r nextBoolean.
+ "
+
+ "
+ |r bag|
+ r := RandomGenerator new.
+ bag := Bag new.
+ 1000000 timesRepeat:[
+ bag add:(r nextBoolean).
+ ].
+ Transcript showCR:bag contents
+ "
+
+ "Created: / 11.11.1999 / 09:25:39 / stefan"
+ "Modified: / 12.11.1999 / 17:22:01 / stefan"
+!
+
+nextByte
+ "get the next random byte"
+
+ ^ RandFile nextByte
+
+ "
+ RandomGenerator new nextByte
+ "
+
+ "Created: / 11.11.1999 / 09:25:39 / stefan"
+!
+
+nextBytes:cnt
+ "get the next cnt random bytes"
+
+ ^ RandFile nextBytes:cnt.
+
+ "
+ RandomGenerator new nextBytes:4
+ "
+
+ "Created: / 11.11.1999 / 09:25:39 / stefan"
+ "Modified: / 11.11.1999 / 09:52:26 / stefan"
+!
+
+nextInteger
+ "return the next integral random number,
+ in the range 0 .. 16r3FFFFFFF."
+
+ |res|
+
+ res := self nextBytes:4.
+ ^ ((((((res at:1) bitAnd:16r3F) * 256) + (res at:2)) * 256) + (res at:3)) * 256 + (res at:4)
+
+
+
+ "
+ |r|
+ r := RandomGenerator new.
+ Transcript showCR:r nextInteger.
+ Transcript showCR:r nextInteger.
+ Transcript showCR:r nextInteger.
+ Transcript showCR:r nextInteger.
+ "
+
+ "Modified: / 11.11.1999 / 10:08:10 / stefan"
+!
+
+nextIntegerBetween:start and:stop
+ "return an integral random number between start and stop"
+
+ |rnd|
+
+ rnd := self next.
+ rnd := rnd * ((stop - start) asFloat + 1.0).
+ ^ rnd truncated + start
+
+ "
+ |r|
+ r := RandomGenerator new.
+ Transcript showCR:(r nextIntegerBetween:1 and:10).
+ Transcript showCR:(r nextIntegerBetween:1 and:10).
+ Transcript showCR:(r nextIntegerBetween:1 and:10).
+ Transcript showCR:(r nextIntegerBetween:1 and:10).
+ "
+
+ "
+ |r bag|
+ r := RandomGenerator new.
+ bag := Bag new.
+ 1000000 timesRepeat:[
+ bag add:(r nextIntegerBetween:-1 and:1).
+ ].
+ Transcript showCR:bag contents
+ "
+
+ "Created: / 11.11.1999 / 10:28:36 / stefan"
+!
+
+nextMatchFor: aNumber
+ "generate the next random, return true iff it has the same
+ value as aNumber. Redefined to avoid endless reading."
+
+ ^self next = aNumber
+
+ "Created: / 11.11.1999 / 10:29:32 / stefan"
+! !
+
+!RandomGenerator methodsFor:'writing'!
+
+nextPut:something
+ "change the random pool by feeding in something.
+ Something should be some unpredictable, random event.
+ Ignored here"
+
+
+!
+
+nextPutAll:something
+ "change the random pool by feeding in something.
+ Something should be some unpredictable, random event.
+ Ignored here"
+
+! !
+
+!RandomGenerator class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libbasic2/RandomGenerator.st,v 1.1 2006-03-10 08:51:39 stefan Exp $'
+! !
+
+RandomGenerator initialize!