这是我的代码(程序集x8086,而不是MIPS,我正在使用emu8086)在屏幕上显示32位数字。当然,基本算法如下:
Input: Number
Set r=0,q=Number,counter=0;
while q > 0 do
divide q by 10
q <- Quotidient, r <- Remainder;
push r;
counter = counter + 1;
end while
while counter > 0 do
pop r;
counter = counter - 1;
display
end while但是问题是,在x8086处理器上,所有寄存器都是16位的.因此,使用div命令进行32位数的除法没有简单的方法(实际上有一些解决方案,但我发现它们很复杂)。因此,我决定分别处理32位数字的高低部分:
Let A be the number in question, we now divide by 10:
A = q*10 + r (0 <= r <= 9)
now separate A into the high and low parts:
A_high * 2^16 + A_low = q*10 + r (0 <= r <= 9)
our task is to find q and r. To do that we first divide the high part:
A_high = q_high * 10 + r_high (0<= r_high <= 9)
=> A_high * 2^16 = (q_high*2^16)*10 + r_high * 2^16 . Note that r_high is from 0 to 9, so to divide r_high * 2^16 by 10, we simply need to perform the calculations and then store the results in a lookup table! The result:
r_high * 2^16 = q_high_redundant * 10 + r_high_redundant (0 <= r_high_redundant <= 9) (found by using a lookup table) (an interesting note: q_high_redundant is only 16 bits!)
Now divide the low part:
A_low = q_low * 10 + r_low
=> A = A_high * 2^16 + A_low = (q_high*2^16 + q_low + q_high_redundant)*10 + r_low + r_high_redundant
Now you just have to divide r_low + r_high_redundant and add in to the quotient, then you get the results.这是我的代码,请给我一些关于美学,代码优化,.非常感谢:
;Written by Dang Manh Truong
.stack 100h
.data
base_10 dw 10
var_32bits_high dw 0
var_32bits_low dw 0
quotidient_32bits_high dw 0
quotidient_32bits_low dw 0
negate_mask equ 0FFFFh
lowest_signed_32bits_high dw 8000h
lowest_signed_32bits_low dw 0000h
lowest_signed_32bits_string dw "-2147483648$"
qhigh dw 0
rhigh dw 0
qlow dw 0
rlow dw 0
qhigh_redundant dw 0
rhigh_redundant dw 0
q_0 dw 0
qhigh0 equ 0h
rhigh0 equ 0h
qhigh1 equ 1999h
rhigh1 equ 6h
qhigh2 equ 3333h
rhigh2 equ 2h
qhigh3 equ 4CCCh
rhigh3 equ 8h
qhigh4 equ 6666h
rhigh4 equ 4h
qhigh5 equ 8000h
rhigh5 equ 0h
qhigh6 equ 9999h
rhigh6 equ 6h
qhigh7 equ 0B333h
rhigh7 equ 2h
qhigh8 equ 0CCCCh
rhigh8 equ 8h
qhigh9 equ 0E666h
rhigh9 equ 4h
.code
main proc
;Initialization
mov ax,@data
mov ds,ax
;example: 7654321 = 0074CBB1h
; mov ax,74h
; mov var_32bits_high,ax
; mov ax,0CBB1h
; mov var_32bits_low,ax
;example: 10223803 = 009C0BBh
; mov ax,9Ch
; mov var_32bits_high,ax
; mov ax,0BBh
; mov var_32bits_low,ax
;example: 32763
; mov ax,0h
; mov var_32bits_high,ax
; mov ax,32763
; mov var_32bits_low,ax
;example: 86420 = 00015194h
; mov ax,1h
; mov var_32bits_high,ax
; mov ax,5194h
; mov var_32bits_low,ax
;example: 2147483647 (2^31 - 1) = 7FFFFFFFh
; mov ax,7FFFh
; mov var_32bits_high,ax
; mov ax,0FFFFh
; mov var_32bits_low,ax
;example: -2147483648 (-2^31)= 80000000h
; mov ax,8000h
; mov var_32bits_high,ax
; mov ax,0000h
; mov var_32bits_low,ax
;example: -1 = FFFF FFFFh
mov ax,0FFFFh
mov var_32bits_high,ax
mov ax,0FFFFh
mov var_32bits_low,ax
mov ax,0
mov bx,0 ;bx: quotidient_32bits_high
mov dx,0 ;dx: quotidient_32bits_low
mov cx,0 ;counter = 0
;16bits or 32bits ?
mov ax,var_32bits_high
cmp ax,0
jne _32bits_routine
jmp _16bits_routine
;;;
_32bits_routine:
mov cx,0
;if == -2147483648 (-2^31)
mov ax,var_32bits_high
cmp ax,lowest_signed_32bits_high
jne check_if_neg
mov ax,var_32bits_low
cmp ax,lowest_signed_32bits_low
jne check_if_neg
;then
lea dx,lowest_signed_32bits_string
mov ah,9
int 21h
jmp return_to_dos
;if < 0
check_if_neg:
mov ax,var_32bits_high
cmp ax,0
jnl preparations
;then print "-" ...
mov ah,2
mov dl,'-'
int 21h
;... and negate number
mov ax,var_32bits_high
xor ax,negate_mask
mov var_32bits_high,ax
mov ax,var_32bits_low
xor ax,negate_mask
inc ax
mov var_32bits_low,ax
jnc preparations
mov ax,var_32bits_high
inc ax
mov var_32bits_high,ax
preparations:
mov ax,var_32bits_high
mov quotidient_32bits_high,ax
mov ax,var_32bits_low
mov quotidient_32bits_low,ax
while_32bits:
; while >0 do
mov ax,quotidient_32bits_high
cmp ax,0
jne div_high_part
mov ax,quotidient_32bits_low
cmp ax,0
jne div_high_part
jmp print_char
div_high_part:
;divide high part
mov dx,0
mov ax,quotidient_32bits_high
div base_10
mov qhigh,ax
mov rhigh,dx
;case rhigh
mov ax,rhigh
cmp ax,0
je _rhigh0
cmp ax,1
je _rhigh1
cmp ax,2
je _rhigh2
cmp ax,3
je _rhigh3
cmp ax,4
je _rhigh4
cmp ax,5
je _rhigh5
cmp ax,6
je _rhigh6
cmp ax,7
je _rhigh7
cmp ax,8
je _rhigh8
cmp ax,9
je _rhigh9
_rhigh0:
mov ax,qhigh0
mov qhigh_redundant,ax
mov ax,rhigh0
mov rhigh_redundant,ax
jmp _aftercase
_rhigh1:
mov ax,qhigh1
mov qhigh_redundant,ax
mov ax,rhigh1
mov rhigh_redundant,ax
jmp _aftercase
_rhigh2:
mov ax,qhigh2
mov qhigh_redundant,ax
mov ax,rhigh2
mov rhigh_redundant,ax
jmp _aftercase
_rhigh3:
mov ax,qhigh3
mov qhigh_redundant,ax
mov ax,rhigh3
mov rhigh_redundant,ax
jmp _aftercase
_rhigh4:
mov ax,qhigh4
mov qhigh_redundant,ax
mov ax,rhigh4
mov rhigh_redundant,ax
jmp _aftercase
_rhigh5:
mov ax,qhigh5
mov qhigh_redundant,ax
mov ax,rhigh5
mov rhigh_redundant,ax
jmp _aftercase
_rhigh6:
mov ax,qhigh6
mov qhigh_redundant,ax
mov ax,rhigh6
mov rhigh_redundant,ax
jmp _aftercase
_rhigh7:
mov ax,qhigh7
mov qhigh_redundant,ax
mov ax,rhigh7
mov rhigh_redundant,ax
jmp _aftercase
_rhigh8:
mov ax,qhigh8
mov qhigh_redundant,ax
mov ax,rhigh8
mov rhigh_redundant,ax
jmp _aftercase
_rhigh9:
mov ax,qhigh9
mov qhigh_redundant,ax
mov ax,rhigh9
mov rhigh_redundant,ax
jmp _aftercase
_aftercase:
;divide low part
mov ax,0
mov q_0,ax
mov dx,0
mov ax,quotidient_32bits_low
div base_10
mov qlow,ax
mov rlow,dx
mov ax,rlow
add ax,rhigh_redundant
;if remainder >= 10
cmp ax,base_10
jl after_if
sub ax,base_10
mov dx,1
mov q_0,dx
after_if:
mov rlow,ax
mov ax,q_0
add ax,qlow
mov qlow,ax
jnc label1
mov ax,qhigh
inc ax
mov qhigh,ax
label1:
mov ax,qlow
add ax,qhigh_redundant
mov qlow,ax
jnc label2
mov ax,qhigh
inc ax
mov qhigh,ax
label2:
;push remainder to stack
mov ax,rlow
push ax
inc cx
mov ax,qhigh
mov quotidient_32bits_high,ax
mov ax,qlow
mov quotidient_32bits_low,ax
jmp while_32bits
;;;
_16bits_routine:
mov ax,var_32bits_low
mov bx,0 ;bx: quotient
mov cx,0
while_loop:
cmp ax,0
je print_char
mov dx,0
div base_10
mov bx,ax ;ax stores quotidient
mov ax,dx ;dx stores remainder
;push remainder
push ax
;counter = counter + 1
inc cx
;numerator = quotidient
mov ax,bx
jmp while_loop
print_char:
cmp cx,0
je return_to_dos
pop ax
;because at this point 0 <= ax <= 9, setting ah = 2 does not change the results
mov ah,2
mov dl,al
add dl,30h ;0-> '0',1->'1',....
int 21h
dec cx
jmp print_char
return_to_dos:
mov ah,4ch
int 21h
main endp
end main发布于 2017-03-19 22:14:13
让我们首先关注16位版本。
CX是否为零。AL寄存器中。我不会在下面的代码中使用它,因为直接在DX寄存器中弹出更短一些。xor自己来完成。test,然后决定零标志(ZF)的状态。所有这些加在一起:
mov ax, var_32bits_low
xor cx, cx
repeat_loop:
xor dx, dx
div base_10
push dx ;push remainder
inc cx ;counter = counter + 1
test ax, ax
jnz repeat_loop
print_char:
pop dx
add dl, 30h ;0 -> '0', 1 ->'1',...
mov ah, 02h ;DOS.PrintChar
int 21h
loop print_char请注意,编写尾注释而不是全行注释可以提供更清晰、更易读的代码。此外,装配编程中的所有内容都是对齐。非常非常重要!
var_32bits_high dw 0 var_32bits_low dw 0 quotidient_32bits_high dw 0 quotidient_32bits_low dw 0 negate_mask equ 0FFFFFh lowest_signed_32bits_high dw 8000 H lowest_signed_32bits_low dw 00h lowest_signed_32bits_string dw "-2147483648$“
以下是以下几点意见,只需看一下这个项目的这一小部分:
db而不是dw来定义。这是个错误。mov ax,0 mov bx,0 ;bx: quotidient\_32bits\_high mov dx,0 ;dx: quotidient\_32bits\_low mov cx,0 ;counter = 0 ;16bits or 32bits ? mov ax,var\_32bits\_high cmp ax,0 jne \_32bits\_routine jmp \_16bits\_routine
如前所述,使用xor reg, reg清除寄存器。
此外,您可以直接将内存与直接内存进行比较,不需要使用寄存器进行比较。
如果你写了(短)16位版本之上的(长)32位版本,条件跳转可以很容易地达到32位版本。
xor ax, ax
xor bx, bx ;bx: quotidient_32bits_high
xor dx, dx ;dx: quotidient_32bits_low
xor cx, cx ;counter = 0
cmp var_32bits_high, 0 ;16bits or 32bits ?
jne _32bits_routine
_16bits_routine:
...
_32bits_routine:
...您会同意,关于16位版本的很多内容也适用于32位版本。老实说,我发现它在评论上太缺乏了,所以我不太愿意对它进行彻底的审查。不过,我将指出下一个优化:
;;;和否定数mov ax,var_32bits_high xor ax,negate_mask mov var_32bits_high,ax
因为negate_mask只是0FFFFFFh,所以这段代码可以编写成一个简单的not。
not var_32bits_high在这里,您只想在前面的操作有进位时增加qhigh变量
jnc label1 mov ax,qhigh inc ax mov qhigh,ax label1:
使用AddWithCarry adc指令编写这个非常简单的代码:
adc qhigh, 0发布于 2017-03-22 05:20:19
这是罗兰工作的直接翻译(java -> asm)。为了清晰起见,我没有做任何努力来优化(尽管有巨大的诱惑)。注释是相关的java行。
请注意,尽管我很担心,但这确实正确地工作了:
; using 123456789 aka 75B CD15
mov dx, 075bh
mov ax, 0cd15h
; input:
; dx:ax = number to be divided by 10
; output:
; dx:ax = old dx:ax div 10
; bx = remainder
; cx, si, di, flags undefined
; cx = 10;
mov cx, 10
; si = dx;
mov si, dx
; di = (short) ((ax >> 8) & 0xff);
mov di, ax
shr di, 8
and di, 0ffh
; bx = (short) (ax & 0xff);
mov bx, ax
and bx, 0ffh
; dx = 0;
mov dx, 0
; ax = si;
mov ax, si
; udiv_cx();
div cx
; si = ax;
mov si, ax
; ax = (short) (((dx & 0xff) << 8) | di);
mov ax, dx
and ax, 0ffh
shl ax, 8
or ax, di
; dx = 0;
mov dx, 0
; udiv_cx();
div cx
; di = ax;
mov di, ax
; ax = (short) (((dx & 0xff) << 8) | bx);
mov ax, dx
and ax, 0ffh
shl ax, 8
or ax, bx
; dx = 0;
mov dx, 0
; udiv_cx();
div cx
; cx = ax;
mov cx, ax
; bx = dx;
mov bx, dx
; dx = si;
mov dx, si
; ax = di;
mov ax, di
; ax <<= 8;
shl ax, 8
; ax |= cx;
or ax, cx在输出方面,dx:ax是BC614E(又名12345678),正如承诺的那样。我没有对此进行广泛的测试,但这似乎是有道理的。既然我有了翻译,我就想和大家分享。
发布于 2017-03-19 23:42:59
在我看来,代码看起来太长了。因此,我实现了一个不同的算法。我用Java编写了它,但是将它转换成8086程序集应该是很简单的。
public class Div32 {
short ax, bx, cx, dx, si, di;
// input:
// dx:ax = number to be divided by 10
// output:
// dx:ax = old dx:ax div 10
// bx = remainder
// cx, si, di, flags undefined
void udiv32_10() {
cx = 10;
si = dx;
di = (short) ((ax >> 8) & 0xff);
bx = (short) (ax & 0xff);
dx = 0;
ax = si;
udiv_cx();
si = ax;
ax = (short) (((dx & 0xff) << 8) | di);
dx = 0;
udiv_cx();
di = ax;
ax = (short) (((dx & 0xff) << 8) | bx);
dx = 0;
udiv_cx();
cx = ax;
bx = dx;
dx = si;
ax = di;
ax <<= 8;
ax |= cx;
}
// emulates the 8086 "udiv cx" instruction, ignoring overflow,
// since that cannot happen in this program
void udiv_cx() {
int x = (dx & 0xffff) << 16 | (ax & 0xffff);
ax = (short) (x / cx);
dx = (short) (x % cx);
}
void print32() {
byte[] out = new byte[20]; // to be allocated on the call stack
int outptr = 20;
out[--outptr] = '其基本思想是提供一个做32位除法的函数.在那之后,剩下的就变得简单了。要计算aa:bb:cc:dd / 10,代码如下:t1 = aa:bb % 10
aa:bb = aa:bb / 10
t2 = t1:cc % 10
cc = t1:cc / 10
rem = t2:dd % 10
dd = t2:dd / 10; // string terminator for int 21h, function 09h
do {
udiv32_10();
out[--outptr] = (byte) ((bx & 0xff) + '0');
} while (ax != 0);
System.out.println(new String(out, outptr, 20 - outptr));
}
void testPrint() {
int x = 123456789;
dx = (short) (x >> 16);
ax = (short) (x & 0xffff);
print32();
}
public static void main(String[] args) {
new Div32().testPrint();
}
}其基本思想是提供一个做32位除法的函数.在那之后,剩下的就变得简单了。
要计算aa:bb:cc:dd / 10,代码如下:
A1
https://codereview.stackexchange.com/questions/157926
复制相似问题