📄 random.asm
字号:
TITLE RANDOM - Random number generator and RANDOMIZE
page ,132
;***
; RANDOM - Random number generator and RANDOMIZE
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; BASIC Syntax mapping to included runtime entry points:
;
;
; - RANDOMIZE Statement - calls B$RNZ1 if parm
;
; Example:
;
; RANDOMIZE 1
; -----------
; |
; B$RNZ1
;
;
; - RND Function - calls B$RND0 if no parm, B$RND1 otherwise:
;
; v = RND[(x)]
;
; Examples:
;
; RND RND(1)
; --- ------
; | |
; B$RND0 B$RND1
;
;
; Algorithm:
;
; We use the "linear congruential" method for random numnber generation. The
; formula is:
;
; x1 = (x0 * a + c) mod 2^24
;
; where
;
; x1 = is a new random number in the range [0..1^24]
; x0 = the previous random number (or the seed, for the first one)
; a = 214,013
; c = 2,531,011
;
; The RND function returns a floating point number:
;
; x1 / (2^24)
;
; which changes the range to [0..1].
;
;******************************************************************************
INCLUDE switch.inc
INCLUDE rmacros.inc ; Runtime Macro Defintions
;Code segments
useSeg INIT_CODE
useSeg MT_TEXT
useSeg DV_TEXT
;Data segments
useSeg CONST
useSeg _DATA
useSeg <XIB> ; XIB and XIE must bracket XI!
useSeg <XI> ; initializer segment
useSeg <XIE>
INCLUDE seg.inc
INCLUDE compvect.inc
INITIALIZER B$xMTINI ;put B$xMTINI in initializer list
INCLUDE messages.inc ; message symbols
SUBTTL Data definitions
page
sBegin CONST
staticW RndA,<43FDH,0003H> ;[4] Double word - 343FDH = 214013D
staticW RndC,<9EC3H,0026H> ;[4] Double word - 269EC3H = 2531011D
.8087
staticD FP_2T24,16777216.0
sEnd ;CONST
sBegin _DATA
externD b$RndVar ; Random number seed
externW B$AC
externW b$run_disp ; Runtime initialization dispatch table
sEnd ;_DATA
SUBTTL code externals
page
sBegin DV_TEXT
externNP B$NearRet ;for disp vectors in compvect.inc
sEnd DV_TEXT
assumes CS,INIT_CODE
sBegin INIT_CODE
;***
;B$xMTINI - Math initializer
;PLM B$xMTINI()
;
;Purpose:
; Initializer for Math component. This routine is called
; by the Crt0 startup before _main is called. It will update the
; indirect dispatch tables for the Math routines. This
; insures that the only time that Math is accessed is when
; this module is linked into the user program.
;
;Entry:
; None.
;
;Exit:
; Appropriate dispatch vectors filled.
;
;Uses:
; None.
;
;Exceptions:
; None.
;****
cProc B$xMTINI,<FAR>
cBegin
;
; update "RUN" time initialization dispatch address to B$MTRUNINI
;
MOV WORD PTR [b$run_disp].MT_RVEC,MT_TEXTOFFSET B$MTRUNINI
cEnd
sEnd INIT_CODE
SUBTTL Math RUNtime interpreter initialization
PAGE
assumes CS,MT_TEXT
sBegin MT_TEXT
;***
;B$MTRUNINI - Do RUN time initialization for Math.
;void pascal B$MTRUNINI()
;
;Purpose:
; Initializes random number seed. This routine
; routine gets called during initialization and during RUN.
;
;Entry:
; None.
;
;Exit:
; None.
;
;Uses:
; None.
;
;Exceptions:
; None.
;****
cProc B$MTRUNINI,<PUBLIC,NEAR>
cBegin
MOV [WORD PTR b$RndVar],0 ;re-init random number
MOV [WORD PTR b$RndVar+2],5 ;seed
cEnd
SUBTTL RND interfaces -- B$RND0 & B$RND0
page
;*** [2]
;B$RND1, B$RND0 - RND function
;R4 B$RND1(R4 RndParm)
;R4 B$RND0(void)
;
;Purpose:
; Both B$RND1 & B$RND0 return a random number. If the argument given
; by the user is positive (or B$RND0), this routine returns the next
; random in sequence. If the argument is zero, it returns the same as
; the previous one. If the argument is negative, it starts a new pseudo
; random sequence.
;Entry:
; None if B$RND0.
; R4 RndParm on stack if B$RND1.
;Exit:
; [AX] = *R4 random number in [0,1)
;Exceptions:
;
;*******************************************************************************
cProc B$RND0,<PUBLIC,FAR,FORCEFRAME>
cBegin
cCall GetNextRnd ; on return, AX=*Rndnum
cEnd ; exit
page
cProc B$RND1,<PUBLIC,FAR>
ParmD RndParm ;[2] R4
cBegin ; set up the stack frame
MOV AX,SEG_RndParm ; fetch high word of R4 parm
OR AX,AX ; Microsoft IEEE: if high word of s.p. is 0,
; the number is 0
JZ SameNum ;input is 0; return same result as last time
JNS NewRnd ; Brif input positive, give next in sequence
MOV DX,OFF_RndParm ; fetch low word of R4 parm
ADD DL,AH ;[4] fold m.s.b. into l.s.b.
ADC DH,0
ADC AL,0
XOR AH,AH ; new 24-bit integer seed in AX:DX
MOV [WORD PTR b$RndVar],DX
MOV [WORD PTR b$RndVar+2],AX
NewRnd:
cCall GetNextRnd ; on return AX=*RndNum
JMP SHORT RndExit
SameNum:
cCall MakeFloat ; on return AX=*RndNum
RndExit:
cEnd ; clean stack and exit to caller
SUBTTL RND supporting routine -- GetNextRnd & MakeFloat
page
;***
;GetNextRnd -- get next random number
;MakeFloat -- make the number in [b$RndVar] into a R4
;
;Purpose:
; Get next random number in sequence.
;Entry:
; [b$RndVar] has the seed.
;Exit:
; [AX] = *B$AC which contains the R4 result
;Exceptions:
; none
;*******************************************************************************
cProc GetNextRnd,<NEAR>
cBegin
PUSH DI
MOV AX,[WORD PTR b$RndVar] ;low half of previous number
MOV CX,[RndA] ;low half of A
MUL CX
XCHG AX,DI ;save low half in DI
MOV BX,DX ; high half in BX
MOV AX,[WORD PTR b$RndVar+2] ;high half of previous
MUL CX
ADD BX,AX ;sum partial products
MOV AX,[RndA]
MUL [WORD PTR b$RndVar]
ADD BX,AX ;last partial product (since we're mod 2^24)
ADD DI,[RndC] ;add in constant C
ADC BL,BYTE PTR [RndC]
XOR BH,BH ;extended 24-bit number to 32 bits for NORM
MOV DX,DI ;number in BX:DX
MOV [WORD PTR b$RndVar],DX ;save for next time
MOV [WORD PTR b$RndVar+2],BX
POP DI
MakeFloat:
FILD b$RndVar ; put 24-bit integer on numeric stack
FDIV FP_2T24 ; ST0 = seed/2^24
MOV BX,OFFSET DGROUP:B$AC
FSTP DWORD PTR [BX] ; put s.p. equivalent into FAC
XCHG AX,BX ; result is *R4 in AX
FWAIT ; ensure result in RAM prior to return
cEnd ; exit to caller
SUBTTL RANDOMIZE interface - B$RNZ1
page
;***[6]
;B$RNZP - RANDOMIZE statement
;void B$RNZP (R8 SeedNum)
;
;Purpose:
; The number is set into the middle word of the current random
; number as the seed for the next one.
;Entry:
; R8 SeedNum
;Exit:
; A new seed is created in RndVar, based on the seed value at entry
; and the least significant 2-words of the input parameter.
;Exceptions:
; none
;*******************************************************************************
cProc B$RNZP,<PUBLIC,FAR>
ParmQ SeedNum ; R8 seed number
cBegin
LEA BX,SeedNum+4 ; get MOST significant digits
MOV AX,[BX] ; get word of D.P. number
XOR AX,[BX+2] ; xor with the next word
MOV [WORD PTR b$RndVar+1],AX ; replace middle word of current s.p. seed
; with this value - - now we're reseeded.
cEnd ; exit
sEnd ;MT_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -