The QBasic Forum     RULES     Other Subforums, Links and Downloads    Index of Threads

 Return to Index  

mRnd# - a function which generates an almost endless list of random numbers.

September 10 2007 at 7:20 PM
  (Login Kewbie)
R


Response to ProgramList Kewbie

DECLARE FUNCTION mRnd# (parm AS LONG)
'Test code for checking out the mRnd# function

'Test 1 prints an unlegended grid of the counts for each value from
'0 to 255 (00 to FF).

'Test 2 checks for strings of 3 or more of the same byte value

'Test 3 tests the repeat last number functionality

DO
  DO
    INPUT "Test 1, 2 or 3? (0 to quit) ", Test%
  LOOP UNTIL Test% > -1 AND Test% < 4
  IF Test% = 0 THEN END

  REDIM ra%(0 TO 255)
  
  INPUT "Enter seed: ", x&
  x& = -ABS(x&)
  x# = mRnd#(x&)

  IF Test% = 1 THEN 'run Test 1
    FOR rdx% = 1 TO 8192
      Rn% = INT(mRnd#(1) * 256)
      ra%(Rn%) = ra%(Rn%) + 1
    NEXT rdx%

    PRINT : PRINT

    zCount& = 0

    FOR rdx% = 0 TO 255
      IF rdx% MOD 16 = 0 THEN PRINT
      PRINT USING "####&"; ra%(rdx%); " ";
      IF ra%(rdx%) = 0 THEN zCount& = zCount& + 1
    NEXT rdx%

    PRINT
    PRINT "Total numbers in range with no hits ="; zCount&
  ELSEIF Test% = 2 THEN 'run Test 2
    Ln% = -1
    FOR rdx& = 1 TO 1000000
      Rn% = INT(mRnd#(1) * 256)
      IF Ln% = Rn% THEN
        Lc% = Lc% + 1
      ELSE
        IF Lc% > 2 THEN
          PRINT Ln%; "repeated"; Lc%; "times."
        END IF
        Lc% = 0
        Ln% = Rn%
      END IF
    NEXT rdx&
    PRINT : PRINT "End of run"
    ELSE 'run Test 3
      FOR rdx% = 1 TO 10
        PRINT mRnd#(1);
        FOR rdx& = 1 TO rdx%
          PRINT mRnd#(0);
        NEXT rdx&
        PRINT : PRINT
      NEXT rdx%
  END IF
LOOP
END 

FUNCTION mRnd# (parm AS LONG)
'mRnd# - generate random numbers using multiple generators
'Generator 0 is used to select which of the generators 1 through
'MAXGEN will be used to get the next random number

'The value passed to the function determines the action performed
'by mRnd#.  Any positive value returns the next random number.  Zero
'returns the last random number generated.  A negative number seeds
'all of the generators from 0 to MAXGEN.

'Because the array doesn't get dimensioned until the generators are
'seeded, a negative value must be passed to mRnd# before any random
'number calls are issued, otherwise the function will crash with a
'"subscript out of range" error.

'The numbers returned by mRnd# are not evenly distributed.  I have
'found that a large number for MAXGEN at least eliminates the number
'of complete misses for a range of 0 - 255.  As Mac pointed out,
'these "gaps" should not make a significant difference for encryp-
'tion purposes, although for game programming it might be a problem.

'Still considering encryption, strings of the same number could be
'a problem, and this would need to be alleviated by the encryption
'program.

'Running Test two (Test% = 2) checks the output of a million numbers,
'and with the seeds that I randomly keyed in, there were no instancese
'of numbers repeated more than once in the range 0 - 255 (i.e. three
'of the same number on three successive calls)
  
  'number of generators, not including 0
  CONST MAXGEN = 4096
                
  'array for saving seeds
  STATIC Seed() AS DOUBLE

  'last random number, working copy of parm argument
  STATIC lRnd AS DOUBLE, prm AS DOUBLE

  'random number, seed index, work variable
  DIM Rn AS DOUBLE, Sd AS DOUBLE, Temp AS DOUBLE

  IF parm > 0 THEN 'return next random number
    'get number of generator to use
    Sd = 0: GOSUB RandomNum
    'from 1 to MAXGEN.  generate number
    Sd = INT(Rn * MAXGEN) + 1: GOSUB RandomNum

    'save last generated number
    lRnd = Rn
  ELSEIF parm < 0 THEN 'seed random number generators
    'create/clean up array of seeds
    REDIM Seed(0 TO MAXGEN) AS DOUBLE

    'make key positive
    prm = -parm
    'place key in correct range (is this necessary?)
    IF prm > 16777216 THEN prm = prm MOD 16777216
    'seed generator 0 with given seed
    Seed(0) = ABS(parm)

    'generate a seed for each generator
    FOR lRnd = 1 TO MAXGEN
      'generate a random number from previous generator
      Sd = lRnd - 1: GOSUB RandomNum
      'place that number in current generator's seed
      Seed(Sd + 1) = Seed(Sd)
    NEXT lRnd
    'every call to mRnd# must return a random number, even
    'seeding calls, which always return the first number
    'generated by the last generator
    Sd = MAXGEN: GOSUB RandomNum
    lRnd = Rn
 'ELSE return previous number
    'nothing to do here, number statically saved from last call
  END IF

  'set function return value
  mRnd# = lRnd
  'and return to caller
  EXIT FUNCTION

RandomNum:
  Temp = (16598013# * Seed(Sd) + 12820163)
  Seed(Sd) = Temp - INT(Temp / 16777216) * 16777216
  Rn = Seed(Sd) / 16777216
  RETURN
END FUNCTION


    
This message has been edited by Kewbie on Sep 10, 2007 7:21 PM


 
 Respond to this message