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