在汇编中生成随机数

4

我刚接触汇编语言,但是在生成随机数方面遇到了问题。

我的代码很简单:它生成100个在0-25范围内的数字,并将它们存储在一个数组中。

我遇到的问题是,当我在emu8086汇编器上运行时,它能够成功地生成100个随机数,并将它们存储在数组中。但是当我在masm611汇编器上运行时,它每4个周期就会生成一个新的随机数。这意味着数组中的值连续出现4次相同的数字,然后才存储下一个随机数。

以下是我的代码:

.model small
.stack 100h
.data

range db 25
i db 0                  ;iterator

arr db 15 dup(0)        ; an array

.code
   mov ax,@data
   mov ds,ax

   mov bx,offset arr    ;getting the adress of the arr in bx
    L1:

    mov ah,2ch      
    int 21h

    mov ah,0  
    mov al,dl            ;using dl by seeing  2ch details
    div range            ; so the number is in range


    mov [bx],ah          ;ah has remainder as using 8 bits div and  
    inc bx               ;moving to the next index

    inc i
    cmp i,100
    jbe L1


mov ah,4ch               ;returning control
int 21h 
end

我的代码有问题吗?我需要添加些什么吗?谢谢。


3
据我所知,系统定时器每1/18.2秒才会更改一次。直接基于此返回值似乎不是一个很好的想法。 - Michael
2
使用RDRAND指令!;-) - Nayuki
@Michael,我应该怎么做? - Hamza Anis
1
不要依赖外部因素(例如您的计时器)。实现一些众所周知的随机数生成器,例如LFSR。此外,请注意,通过使用模运算符将数字适应于范围,数字变得不均匀分布(例如,0..255 mod 240会使数字0..15出现两次)。 - gudok
3
那边的“相关”面板中有几个有用的链接。--->> - Weather Vane
问题通过在迭代中进行延迟来解决。感谢所有人。 - Hamza Anis
2个回答

6
你的代码的主要问题在于它根本不生成随机数。因为系统时钟不是随机数生成器。我会说,它是非常不随机的数字生成器。
程序启动后第一次读取仍然可以被认为是“随机”的,但只有在随机时间手动运行程序时才能这样认为。
接下来的所有数字都不是随机的。
这种方式,从系统时钟读取的值适合用作某些其他算法(伪)随机数生成的种子(起始值)。
随机数(和伪随机数)生成器是一个复杂的话题,需要一些学习。至少从wikipedia开始学起。
顺便说一句,尽管整个主题很复杂,但有些随机数生成器对于初学者程序员来说足够简单。例如middle-square-method。尝试通过将当前种子AX乘以自身并形成下一个数字的结果的中间4个十六进制数字来在汇编语言中实现它:
; here ax contains the previous number

    mul ax
    mov al, ah
    mov ah, dl 

; here ax contains the next pseudo random number.

谢谢,这很有帮助。但是我通过设置一个“虚拟循环”来解决了我的问题,这会导致迭代的延迟。问题在于masm611太快了,在毫秒数以2ch的速度变化之前,它会将值存储在dl寄存器中,即在其改变之前就存储了该值。 - Hamza Anis
4
@HamzaAnis,实际上你并没有解决问题,你只是掩盖了它。 - johnfound

2

在johnfound的回答基础上,您可以通过使用Weyl序列来运行他所描述的中间平方方法,从而构建更加强大的随机数生成器。这是基于Bernard Widynski于2017年4月4日发表的《中间平方Weyl序列RNG》的思想。

以下是一个汇编实现示例:

    mul ax      ; square random number
    add cx, bx  ; calculate next iteration of Weyl sequence
    add ax, cx  ; add Weyl sequence
    mov al, ah  ; get lower byte of random number from higher byte of ax
    mov ah, dl  ; get higher byte of random number from lower byte of dx
    ...         ; use new random number stored in ax

关于以上代码的几点说明:
  • 随机数存储在ax中。
  • 初始种子存储在bx中(例如,您可以使用从系统时钟派生的内容)。种子必须为奇数且8个高位不能为零。
  • Weyl序列存储在cx中,并通过每次迭代添加bx来获得。
与标准的中间平方方法不同,将其与Weyl序列相结合可以防止随机数序列向0收敛。建议阅读上述提及的出版物以获取更多信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接