Random number generator: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
(→‎Linear feedback shift register: prng_xbits generalization)
m (clarify further the role of prng_xbits)
Line 22: Line 22:
;
;
; The value loaded in X controls the quality of randomness.  Each iteration
; The value loaded in X controls the quality of randomness.  Each iteration
; produces another bit worth of entropy.  All 8 bits will produce maximum
; produces another random bit.  All 8 bits will produce maximum entropy,
; entropy, but this value can be lowered to increase speed if you are using
; but this value can be lowered to increase speed if you need only low-order
; only low-order bits.  If using the same value each time (prng), use
; bits.  If using the same value each time (prng), use 8, 7, 4, 2, 1.
; 8, 7, 4, 2, 1. Avoid long runs of 6, 5 and 3, as they shorten the
; Avoid long runs of 6, 5 and 3, as they shorten the sequence by having
; sequence by having common factors with 65535.  If you use different amounts
; common factors with 65535.  If you use different amounts of low-order bits
; of low-order bits each time, such as to produce random numbers in different
; each time, such as random numbers in different ranges in different parts
; ranges in different parts of a game, you can use prng_xbits.
; of a game, you can use prng_xbits to change how many bits are produced
; followed by an AND to drop unused bits.
;  
;  
;
;
Line 59: Line 60:


Past forum discussions of random number generators:
Past forum discussions of random number generators:
* Forum: [http://forums.nesdev.org/viewtopic.php?f=2&t=14499 Quality of the CC65 randomizer]
* Forum: [http://forums.nesdev.org/viewtopic.php?f=2&t=14499 Quality of the CC65 randomizer] (a 23-bit LCG)
* Forum: [http://forums.nesdev.org/viewtopic.php?f=2&t=13172 Which randomizer to use?]
* Forum: [http://forums.nesdev.org/viewtopic.php?f=2&t=13172 Which randomizer to use?]
* Forum: [http://forums.nesdev.org/viewtopic.php?f=10&t=11241 need assistance with random number generator]
* Forum: [http://forums.nesdev.org/viewtopic.php?f=10&t=11241 need assistance with random number generator]
* Forum: [http://forums.nesdev.org/viewtopic.php?f=2&t=9598 CRC routines as PRNGs]
* Forum: [http://forums.nesdev.org/viewtopic.php?f=2&t=9598 CRC routines as PRNGs]

Revision as of 02:41, 11 July 2016

While truly random numbers are difficult to create with a deterministic computer, a pseudorandom number generator, or PRNG, may be used instead, which is technically deterministic, but designed so that the output should appear consistently uncorrelated. There are a wide variety of suitable algorithms.

Typically a starting "seed" is supplied by the program to begin the sequence generated by a PRNG. By finding some way[1] of gathering a suitably unpredictable starting seed, (e.g. counting the time until the user presses a button) the program can start at a different part of the sequence each time it is run, ensuring the user does not have the same experience twice.

Linear feedback shift register

The linear feedback shift register is commonly used as a PRNG on systems like the 6502 which have no hardware multiply capabilities. This rotates a series of bits (the shift register), with the bit coming off the end of the series feeding back into the register as an exclusive-OR operation. By choosing the feedback bits carefully, this can create a sequence that fills the register with every possible value (except 0), allowing relatively long random number sequences using only bitwise operations.

This example is only 16 bits wide, but the sequence length of an LSFR can be doubled with each bit. 24 and 32 bit LSFRs are very practical if extremely long sequences are needed.

; prng
;
; Returns a random 8-bit number in A (0-255), clobbers X (0).
;
; Requires a 2-byte value on the zero page called "seed".
; Initialize seed to any value except 0 before the first call to prng.
; (A seed value of 0 will cause prng to always return 0.)
;
; This is a 16-bit Galois linear feedback shift register with polynomial $002D.
; The sequence of numbers it generates will repeat after 65535 calls.
;
; The value loaded in X controls the quality of randomness.  Each iteration
; produces another random bit.  All 8 bits will produce maximum entropy,
; but this value can be lowered to increase speed if you need only low-order
; bits.  If using the same value each time (prng), use 8, 7, 4, 2, 1.
; Avoid long runs of 6, 5 and 3, as they shorten the sequence by having
; common factors with 65535.  If you use different amounts of low-order bits
; each time, such as random numbers in different ranges in different parts
; of a game, you can use prng_xbits to change how many bits are produced
; followed by an AND to drop unused bits.
; 
;
; Execution time is an average of 125 cycles (excluding jsr and rts)

.zeropage
seed: .res 2       ; initialize 16-bit seed to any value except 0

.code
prng:
	ldx #8     ; iteration count: controls entropy quality (max 8,7,4,2,1 min)
prng_xbits:
	lda seed+0
@bitloop:
	asl        ; shift the register
	rol seed+1
	bcc :+
	eor #$2D   ; apply XOR feedback whenever a 1 bit is shifted out
:
	dex
	bne @bitloop
	sta seed+0
	cmp #0     ; reload flags
	rts

References

Past forum discussions of random number generators: