[net.micro.amiga] Random numbers

steve@amiga.UUCP (Steve B.) (04/11/86)

While browsing through net.micro.amiga the other day, I noticed a simple
random number routine someone had put in thier posting.  This prompted me
to dig through my old 6502 sources for a random number routine I used to
use a lot.  Here, I've converted it from it's old 40 bit format into a 64 bit
format.  I figured you Amigalites out there may find a use for it.  It
appears to have excellent distribution and is OODLES faster than the floating
point equivalents.  I would really be interested if someone who knows all
about random numbers could test out this routine and let me know how good it
is.  I know the old 40 bit version used to repeat once every 8,589,934,592
iterations, thats 272 years worth at one per second.  I have reason to suspect
that a 64 bit version would be better than this.

Note: each routine has two entry points, one for assembler and one for C.
      use the same name for both since the Lattice C compiler adds an '_'
      to the front of any external references.

      Just assemble this thing (assem rnd.asm -o rnd.obj) and then link
      the object file into your C or assembler program.

Well, thats about all, have fun.

	Steve Beats
	Commodore Technology



;=============cut===cut===cut====!====I said CUT dammit!======================

		XDEF	RandomSeed,Random	assembler entry points
		XDEF	_RandomSeed,_Random	C entry points
		CODE
;=============================================================================
; NAME
;    RandomSeed - seed random number generator, call once at beginning of
;		  your program.  CurrentTime provides useful values for this
;
; SYSNOPSIS
;    RandomSeed( SeedValue )
;		    D0
;
; FUNCTION
;    Seeds the random number generator
;
; INPUTS
;    SeedValue - a longword containing any value you like
;
; RESULT
;    Random number generator is initialised
;
; BUGS/LIMITATIONS
;    None that I know of
;
; SEE ALSO
;
;============================================================================

_RandomSeed	MOVE.L	4(SP),D0	entry point for C functions
RandomSeed	ADD.L	D0,D1		user seed in d0 (d1 too)
		MOVEM.L	D0/D1,RND

; drops through to the main random function (not user callable)

LongRnd		MOVEM.L	D2-D3,-(SP)	
		MOVEM.L	RND,D0/D1	D0=LSB's, D1=MSB's of random number
		ANDI.B	#$0E,D0		ensure upper 59 bits are an...
		ORI.B	#$20,D0		...odd binary number
		MOVE.L	D0,D2
		MOVE.L	D1,D3
		ADD.L	D2,D2		accounts for 1 of 17 left shifts
		ADDX.L	D3,D3		[D2/D3] = RND*2
		ADD.L	D2,D0
		ADDX.L	D3,D1		[D0/D1] = RND*3
		SWAP	D3		shift [D2/D3] additional 16 times
		SWAP	D2
		MOVE.W	D2,D3
		CLR.W	D2
		ADD.L	D2,D0		add to [D0/D1]
		ADDX.L	D3,D1
		MOVEM.L	D0/D1,RND	save for next time through
		MOVE.L	D1,D0		most random part to D0
		MOVEM.L	(SP)+,D2-D3
		RTS

;=============================================================================
; NAME
;    Random - returns a random integer in the specified range
;
; SYSNOPSIS
;    RndNum = Random( UpperLimit )
;      D0		  D0
;
; FUNCTION
;    returns a random integer in the range 0 to UpperLimit-1
;
; INPUTS
;     UpperLimit - a long(or short will do) in the range 1-65535
;
; RESULT
;    a random integer is returned to you, real quick!
;
; BUGS/LIMITATIONS
;    range was limited to 1-65535 to avoid problems with the DIVU instruction
;    which can return real wierd values if the result is larger than 16 bits.
;
; SEE ALSO
;
;============================================================================

_Random		MOVE.L	4(SP),D0	C entry point
Random		MOVE.W	D2,-(SP)
		MOVE.W	D0,D2		save upper limit
		BEQ.S	10$		range of 0 returns 0 always
		BSR.S	LongRnd		get a longword random number
		CLR.W	D0		use upper word (it's most random)
		SWAP	D0
		DIVU.W	D2,D0		divide by range...
		CLR.W	D0		...and use remainder for the value
		SWAP	D0		result in D0.W
10$		MOVE.W	(SP)+,D2
		RTS

		BSS
RND		DS.L	2		random number
		END