在 Assembly 中同时生成 2 个随机整数
Generate 2 random integers simultaneously in Assembly
背景
函数 rollCubes
在西洋双陆棋游戏的每一轮中掷出 2 个立方体。
问题
当运行: rollCubes
总是returns 2-2, 4-4
或6-6
.
[编辑]
调试时(执行 turbo debugger
中的每一行): 该函数设法生成两个不同的随机整数,但立方体 1
从未滚动.
这让我想知道是什么阻止 rollCubes
在 运行 可执行文件时生成随机整数。
源代码
proc rollCubes
xor cx, cx
mov [hicube], 0
mov [locube], 0
mov cx, 2
addAgainHigh:
; Random number [0, 3] --> two rolls [0, 6]
mov ax, 40h
mov es, ax
mov ax, es:6Ch ;Random number
and al, 00000011b
cmp al, 0 ;Make sure al isn't 0
je addAgainHigh ;If 0, roll again
add [hicube], al ;add to cube value
loop addAgainHigh
mov cx, 2
addAgainLow:
; Random number [0, 3] --> two rolls [0, 6]
mov ax, 40h
mov es, ax
mov ax, es:6Ch
and al, 00000011b
cmp al, 0
je addAgainLow
add [locube], al
loop addAgainLow
mov al, [locube]
mov ah, [hicube]
ret
endp rollCubes
您的代码读取了一些数字 (BIOS.Timer) 并仅保留可能值 {1,2,3} 的一个子集。重复后得到 {2,3,4,5,6}。 你永远不能这样掷 1
一掷骰子应产生一个从 1 到 6 的数字。
call myRandom ; -> AX = [0,65535]
xor dx, dx
mov cx, 6
div cx ; -> Remainder DX = [0,5]
inc dx ; -> Dice is [1,6]
...
; IN () OUT (ax)
proc myRandom
imul ax, [NextRandom], 25173
add ax, 13849
xor ax, 62832
mov [NextRandom], ax
ret
endp myRandom
此 myRandom 过程中的代码是一个 pseudo random number generator,它将在重复自身之前产生 65536 个唯一的 16 位数字。它很快就会输出相同的数字。
当我 运行 上述代码 80 次时(NextRandom 从 0 开始),我得到以下用于掷骰子的数字:
4,5,6,1,2,3,2,3,4,3, 2,3,6,5,6,3,4,3,4,1
6,5,6,5,4,3,6,1,2,5, 4,5,2,3,6,5,2,1,6,3
6,3,6,3,2,3,2,1,2,5, 2,1,2,3,4,1,6,5,4,1
4,5,4,5,4,1,2,1,2,3, 6,3,6,1,4,1,6,3,6,1
这些数字的分布很好:
1 ~ 13
2 ~ 13
3 ~ 16
4 ~ 12
5 ~ 11
6 ~ 15
[编辑]
When running: rollCubes always returns 2-2, 4-4 or 6-6.
It makes me wonder what prevents rollCubes from producing randoms when running the executable.
线性地址 0040h:006Ch 的 BIOS.Timer 标记每 55 毫秒递增一次。这在计算机中是一个很长的时间,并且因为您的 rollCubes 程序快速连续读取此计数器 4 次 ,您几乎总是会收到相同的它的价值。
这是大多数时候发生的情况:
如果TimerTick恰好以00b
结束
addAgainHigh:
00b reread until it changes to 01b
01b=1 hicube = 0 + 1 + 1 = 2
addAgainLow:
01b=1 locube = 0 + 1 + 1 = 2
如果TimerTick恰好以01b
结束
addAgainHigh:
01b=1 hicube = 0 + 1 + 1 = 2
addAgainLow:
01b=1 locube = 0 + 1 + 1 = 2
如果TimerTick恰好以10b
结束
addAgainHigh:
10b=2 hicube = 0 + 2 + 2 = 4
addAgainLow:
10b=2 locube = 0 + 2 + 2 = 4
如果TimerTick恰好以11b
结束
addAgainHigh:
11b=3 hicube = 0 + 3 + 3 = 6
addAgainLow:
11b=3 locube = 0 + 3 + 3 = 6
When debugging (executing each line inside turbo debugger): the function manages to produce random rolls as should be.
确实,快速继承的问题已经不复存在了!从 Turbo Debugger 中执行程序需要时间。 BIOS.Timer线性地址 0040h:006Ch 处的滴答将(很可能)在程序读取之间增加。
When debugging (executing each line inside turbo debugger): the function manages to produce random rolls as should be.
不是真的!正如我最早的回答中所述,您永远不能以这种方式掷出 1。
因为您的程序抛出了零,以下是您的代码可以通过加法组合两个集合 {1,2,3} 产生的所有总和:
1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
2 + 1 = 3
2 + 2 = 4
2 + 3 = 5
3 + 1 = 4
3 + 2 = 5
3 + 3 = 6
请注意,这样数字的概率非常不同。
背景
函数 rollCubes
在西洋双陆棋游戏的每一轮中掷出 2 个立方体。
问题
当运行: rollCubes
总是returns 2-2, 4-4
或6-6
.
[编辑]
调试时(执行 turbo debugger
中的每一行): 该函数设法生成两个不同的随机整数,但立方体 1
从未滚动.
这让我想知道是什么阻止 rollCubes
在 运行 可执行文件时生成随机整数。
源代码
proc rollCubes
xor cx, cx
mov [hicube], 0
mov [locube], 0
mov cx, 2
addAgainHigh:
; Random number [0, 3] --> two rolls [0, 6]
mov ax, 40h
mov es, ax
mov ax, es:6Ch ;Random number
and al, 00000011b
cmp al, 0 ;Make sure al isn't 0
je addAgainHigh ;If 0, roll again
add [hicube], al ;add to cube value
loop addAgainHigh
mov cx, 2
addAgainLow:
; Random number [0, 3] --> two rolls [0, 6]
mov ax, 40h
mov es, ax
mov ax, es:6Ch
and al, 00000011b
cmp al, 0
je addAgainLow
add [locube], al
loop addAgainLow
mov al, [locube]
mov ah, [hicube]
ret
endp rollCubes
您的代码读取了一些数字 (BIOS.Timer) 并仅保留可能值 {1,2,3} 的一个子集。重复后得到 {2,3,4,5,6}。 你永远不能这样掷 1
一掷骰子应产生一个从 1 到 6 的数字。
call myRandom ; -> AX = [0,65535]
xor dx, dx
mov cx, 6
div cx ; -> Remainder DX = [0,5]
inc dx ; -> Dice is [1,6]
...
; IN () OUT (ax)
proc myRandom
imul ax, [NextRandom], 25173
add ax, 13849
xor ax, 62832
mov [NextRandom], ax
ret
endp myRandom
此 myRandom 过程中的代码是一个 pseudo random number generator,它将在重复自身之前产生 65536 个唯一的 16 位数字。它很快就会输出相同的数字。
当我 运行 上述代码 80 次时(NextRandom 从 0 开始),我得到以下用于掷骰子的数字:
4,5,6,1,2,3,2,3,4,3, 2,3,6,5,6,3,4,3,4,1
6,5,6,5,4,3,6,1,2,5, 4,5,2,3,6,5,2,1,6,3
6,3,6,3,2,3,2,1,2,5, 2,1,2,3,4,1,6,5,4,1
4,5,4,5,4,1,2,1,2,3, 6,3,6,1,4,1,6,3,6,1
这些数字的分布很好:
1 ~ 13
2 ~ 13
3 ~ 16
4 ~ 12
5 ~ 11
6 ~ 15
[编辑]
When running: rollCubes always returns 2-2, 4-4 or 6-6. It makes me wonder what prevents rollCubes from producing randoms when running the executable.
线性地址 0040h:006Ch 的 BIOS.Timer 标记每 55 毫秒递增一次。这在计算机中是一个很长的时间,并且因为您的 rollCubes 程序快速连续读取此计数器 4 次 ,您几乎总是会收到相同的它的价值。
这是大多数时候发生的情况:
如果TimerTick恰好以00b
结束addAgainHigh: 00b reread until it changes to 01b 01b=1 hicube = 0 + 1 + 1 = 2 addAgainLow: 01b=1 locube = 0 + 1 + 1 = 2
如果TimerTick恰好以01b
结束addAgainHigh: 01b=1 hicube = 0 + 1 + 1 = 2 addAgainLow: 01b=1 locube = 0 + 1 + 1 = 2
如果TimerTick恰好以10b
结束addAgainHigh: 10b=2 hicube = 0 + 2 + 2 = 4 addAgainLow: 10b=2 locube = 0 + 2 + 2 = 4
如果TimerTick恰好以11b
结束addAgainHigh: 11b=3 hicube = 0 + 3 + 3 = 6 addAgainLow: 11b=3 locube = 0 + 3 + 3 = 6
When debugging (executing each line inside turbo debugger): the function manages to produce random rolls as should be.
确实,快速继承的问题已经不复存在了!从 Turbo Debugger 中执行程序需要时间。 BIOS.Timer线性地址 0040h:006Ch 处的滴答将(很可能)在程序读取之间增加。
When debugging (executing each line inside turbo debugger): the function manages to produce random rolls as should be.
不是真的!正如我最早的回答中所述,您永远不能以这种方式掷出 1。
因为您的程序抛出了零,以下是您的代码可以通过加法组合两个集合 {1,2,3} 产生的所有总和:
1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
2 + 1 = 3
2 + 2 = 4
2 + 3 = 5
3 + 1 = 4
3 + 2 = 5
3 + 3 = 6
请注意,这样数字的概率非常不同。