RandomGenerator.st
author Stefan Vogel <sv@exept.de>
Thu, 08 Nov 2007 15:03:20 +0100
changeset 1909 c76efba26558
parent 1840 6cc7e54f6a62
child 1925 1db437e31d6e
permissions -rw-r--r--
Methods to get all addresses for a given hostname (multihomed hosts)

"{ 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!