initial checkin
authorStefan Vogel <sv@exept.de>
Fri, 10 Mar 2006 09:51:39 +0100
changeset 1606 ad25ac239337
parent 1605 893af2a9f99e
child 1607 bcc02c697f1c
initial checkin
RandomGenerator.st
--- /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!