program Tausgen ; { Demonstration of Tausworthe Pseudorandom Number Generator 30 April 1985 David P Kirschbaum, Toad Hall 7573 Jennings Lane, Fayetteville NC 28303 on ARPANet: ABN.ISCAMS@USC-ISID See extracts from Professor Thesen's paper (the source of this code) at the end of this program. Expect an initial delay during the initialization of the byte table and offset pointers when the program actually runs. During actual implementation in a program, the table would be initialized only once (until you wanted to reseed again, anyway). If using my simple screen display version below, you have flow control. Enter any key to pause, and enter RETURN to continue. (Your system may stop on its own occasionally if your system XOFFs high-speed printing to the console. Just enter RETURN to continue.) Enter Q or q to end. } {Relax string parameter checking} {V$-} Type Line = string[79] ; Menu = string[25] ; const pminusl = 97 ; {p = 98; q = 27} maxbit = 255 ; maxs = 26 ; Selection : array[1..4] of Menu = ('1 Random Number Display ' , '2 Speed Run (no display)' , '3 Distribution Display ' , '4 Quit ') ; var Ch : Char ; Sentence : Line ; BlankLine : Line ; Halted : Boolean ; Quit : Boolean ; Error : Boolean ; f,s : Integer ; x,y : Integer ; count : Integer ; prandom : Integer ; choice : Integer ; ByteTable : array[0..pminusl]of byte ; RCounter : array[0..maxbit] of Integer ; procedure CenterPrint(Sentence : Line) ; var Centered : Line ; begin Centered := BlankLine ; y := (80 - Length(Sentence)) div 2 ; Insert(Sentence,Centered,y) ; Writeln(Centered) ; end ; procedure PlotXY(var number : integer; value : integer) ; begin x := (number mod 12) * 4 + 12 ; y := (number div 12) + 2 ; GoToXY(x,y) ; Write(value:4) ; end ; {PlotXY} procedure CheckUser ; begin if KeyPressed then begin GoToXY(1,24) ; Read(Ch) ; Quit := Ch in ['Q', 'q'] ; end ; {KeyPressed} end ; {CheckUser} procedure ContPrompt ; begin Writeln ; GoToXY(1,22) ; CenterPrint('Hit any key to continue: ' ) ; Writeln ; GoToXY(54,22) ; Repeat until KeyPressed = True ; end ; procedure TauInit(var f,s : integer) ; var BitIndex : integer ; WorkTable : array[0..pminusl]of byte ; begin for count := 0 to pminusl do begin ByteTable[count] := maxbit ; WorkTable[count] := 0 ; end ; {count loop} f := pminusl ; s := maxs ; Quit := False ; for BitIndex := 1 to 16 do begin CheckUser ; If NOT Quit then begin for count := 1 to 9800 do begin if f < pminusl then f := f + 1 else f := 0 ; if s < pminusl then s := s + 1 else s := 0 ; ByteTable[f] := ByteTable[f] xor ByteTable[s] ; end; {count loop} if BitIndex > 8 then begin ClrScr ; Writeln ; Writeln('Loop ',BitIndex) ; for count := 0 to pminusl do begin if odd(ByteTable[count]) then WorkTable[count] := (WorkTable[count] div 2) + 128 else WorkTable[count] := WorkTable[count] div 2 ; ByteTable[count] := ByteTable[count] div 2 ; PlotXY(count,WorkTable[count]) ; end; {count loop} end ; {BitIndex > 8} end ; {not Quit} end ; {BitIndex loop} ClrScr ; CenterPrint('Final Byte Table.') ; for count := 0 to pminusl do begin ByteTable[count] := WorkTable[count] ; PlotXY(count,ByteTable[count]) ; end; {count loop} f := pminusl ; s := maxs ; end ; {TauInit} function RByte : byte ; begin if f < pminusl then f := f + 1 else f := 0 ; if s < pminusl then s := s + 1 else s := 0 ; RByte := ByteTable[f] ; ByteTable[f] := ByteTable[f] xor ByteTable[s] ; end ; {RByte} {main program [Toad Hall]} begin FillChar(BlankLine,79,chr(32)) ; ClrScr ; CenterPrint('A Toad Hall Demonstration.') ; CenterPrint('of a Tausworthe Pseudorandom Number Generator.') ; CenterPrint('as described by Thesen et al.') ; Writeln ; CenterPrint('Beginning table initialization.') ; TauInit(f,s) ; ContPrompt ; ClrScr ; Writeln ; CenterPrint('Initialization complete.') ; Writeln ; for x := 1 to 4 do CenterPrint(Selection[x]) ; Writeln ; Quit := False ; Error := True ; repeat GoToXY(30,10) ; Write('Enter Selection (1-4): ') ; Readln(choice) ; if choice in [1..4] then Error := False ; if choice = 4 then Quit := True ; until Error = False ; If NOT Quit then begin ClrScr ; CenterPrint('Beginning random number generation.') ; for prandom := 0 to maxbit do RCounter[prandom] := 0 ; { This is a screen display so you (human) can see the numbers. Comment this out, and use the next segment if you want clock timing. Add in your own file-related stuff if you want to collect lots of numbers for some sort of statistical analysis. Easy... but YOU can do it! } if choice = 1 then repeat for y := 5 to 23 do begin If NOT Quit then begin for x := 1 to 16 do begin GoToXY(x * 4,y) ; Write(RByte:4) ; end; {x} CheckUser ; end ; {NOT Quit} end; {y} until Quit = True ; {choice 1} {And if you want to do some timing loops - this sucker is FAST! Kludge in any system clock you have at the beginning and end of this next routine, bring it on line instead of the display one above, and do some timing. On my Z80B CP/M system (Morrow Decision I), wristwatch timing looked like 8 or 9 seconds for the 32000 loop. Prof. Thesen reported 8 seconds on an IBM-PC.} if choice = 2 then begin CenterPrint('30 000 random numbers.') ; Writeln ; CenterPrint('The big hand is pointing to .') ; for count := 1 to 32000 do prandom := RByte ; CenterPrint('The big hand is pointing to .') ; for x := 1 to 20 do Write(' ') ; Write('Completed with count = ',count) ; Writeln(', and last number = ',prandom) ; end ; {choice 2} { And if you want a down-and-dirty analysis of random number distribution, try this one ... } if choice = 3 then repeat CheckUser ; prandom := RByte ; if RCounter[prandom] < maxbit then RCounter[prandom] := RCounter[prandom] + 1 else RCounter[prandom] := 0 ; PlotXY(prandom,RCounter[prandom]) ; until Quit = True ; {choice 3} end ; {not Quit} GoToXY(1,23) ; Writeln ; Writeln ; CenterPrint('Terminating.') ; end. { Algorithms extracted from "Some Efficient Random Number Generators for Microcomputers" by Arne Thesen, Shanshan Sun and Tzyh-Jong Wang Industrial Engineering Department University of Wisconsin-Madison (Released to the Public Domain by Professor Thesen, 23 April 1985 (message on file at Toad Hall)) This is a Tausworthe Generator. Extracts from Prof. Thesen's paper, the implementing demonstration code, and some comments... by David Kirschbaum, Toad Hall (ABN.ISCAMS@USC-ISID "A Tausworthe generator "Tausworthe [5] has suggested a different approach to the generation of pseudo-random integers. This procedure, which operates directly on bits to form a stream of random bits, has been shown to produce random number sequences that (1) have improved statistical properties over LC [linear congruential] generators, and (2) have an arbitrarily long period independent of the word size of the computer used. "Tausworthe generators are not in widespread use. This could be because they are difficult to implement efficiently in a higher level language, or because their improved statistical properties are of marginal utility on larger computers. On microcomputers, the situation is quite different. Here the improvement in period length and in statistical properties is quite substantial, and well written Tausworthe generators are not necessarily more time consuming than other classes of generators. "Algorithm The basic procedure of a Tausworthe type generator is illustrated in Figure 1: B[i-p] B[i-r] B[i] B = . . x . . . . x . . . . x . . . . . | | | +-->xor<--+ | | | +--------------+ "Figure 1: Relationship between bits in a Tausworthe generated bit stream. "Here B is defined as a sequence of bits, and the relationship between individual bits in the sequence is defined in Algorithm 2: B[i] = B[i-r] XOR B[i-p] where: i = any integer r , p = fixed integers with 0