"{ 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"
!
nextCharacters:cnt
"get the next cnt printable characters.
We answer characters in the ascii range (codepoints 32 - 127)"
|bytes string|
bytes := self nextBytes:cnt.
string := String new:cnt.
bytes keysAndValuesDo:[:eachIndex :eachByte|
string at:eachIndex put:(Character value:(eachByte \\ 95 + 32)).
].
^ string
"
RandomGenerator new nextCharacters:8
"
!
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.3 2007-01-24 15:26:41 stefan Exp $'
! !
RandomGenerator initialize!