ОБНОВЛЕНИЕ: Ранее я публиковал способ печати только 16-разрядного числа, но теперь я нашел способ печати и 32-разрядного числа, поэтому я решил удалить предыдущее решение. Вот общая идея:
- Проверьте, является ли число отрицательным или положительным
- Если он отрицательный, отрицать его, используя дополнение до двух. Но мы должны позаботиться о угловом случае: 32-разрядное число со знаком изменяется от -2 ^ 31 до 2 ^ 31-1, поэтому мы видим, что нет положительного эквивалента -2 ^ 31. Таким образом, мы должны выделить этот случай и сохранить соответствующее число (в строковом формате) и распечатать его
- Если оно положительное, то мы многократно делим на 10, берем остаток, помещаем его в стек, затем возвращаем обратно и печатаем каждый номер последовательно (это легко, поскольку Assembly x8086 предоставила соответствующие подпрограммы)
Кстати, в моем коде я также проверил, равна ли 16-битная верхняя часть нулю, а затем перейдем к функции _16bits_routine, которая основана на том же принципе.
Тем не менее, деление на 10 не является тривиальным в 32-разрядных, так как функция div
не поддерживает его, поэтому вот что я делаю:
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