我写了一个程序来获取数组中的最小数字, 但我无法在屏幕上打印它:(( 我认为问题是将其转换为 ASCII。
.model small
.stack 100h
.data
x db 0,5,-1,4,2 ;my array
min db 0 ;variable to store the smallest number
msg db "The min number is: $"
.code
main PROC
mov ax,@data
mov ds,ax
xor cx,cx
mov cl,5 ;set count to 5
mov si,0 ;start at index 0
L1:
mov dl,x[si] ;can't compare memory to memory so I moved x[si] to dl
cmp min,dl ;checks to see if the value in dl is smaller than
;value in min
JNB no
mov min,dl
no:
inc si
loop L1
mov ah,09
mov dx,offset msg ;print the message
int 21h
cmp min,0 ;check if number is negative or positive
JB minus
mov ah,02
mov dl,min
int 21h
minus: ;if minus print the minus sign
mov ah,02
mov dl,'-'
int 21h
*mov ah,02
mov dl,min
or dl,30h ;here's my error can't print value of min
int 21h*
mov ah,04ch ;exit code
int 21h
main ENDP
END main
另外,如果有人有很好的资源或学习80386汇编保护模式的书,请在此处提及:))
你的代码有两个问题(除了显示负数)
1.在 NUM 变量中放置零
如果您的数组包含非零数字怎么办,例如:5, 4, 7, 1
它应该打印 1,因为它是最小数字,但您的代码将打印 0,这在数组中甚至不存在。
2.使用JNB和JB指令
这些指令仅用于正整数,这里有一个看看JNB JB。您必须使用 JNG 和 JG,因为您的数组包含负数。
以下是检查数组中最小数的程序(无论它包含负数还是正数,它都可以在两种情况下工作,并且还显示了如何打印负数):
.model small
.stack 100h
.data
num db 7,5,3,4,2 ;my array
msg db "The min number is: $"
.code
main PROC
mov ax,@data
mov ds,ax
mov ax, 0
mov bl, num [0] ; store first element of array in bl
mov cx, 4
mov si, 1 ; index of second element
calMin:
mov al, num [si]
cmp bl, al
jng continue ; jng is used for signed numbers
mov bl, al ; exchange values if smaller
continue:
inc si
loop calMin
mov ah, 09h
mov dx, offset msg
int 21h
mov cl, bl
neg cl ; 2's complement the min number ( to check if its negative or positive number )
js posNum ; jmp to posNum if sign flag is set
mov bl, cl
jz posNum
negNum:
mov ah, 02h
mov dl, '-' ; print minus symbol if negative number
int 21h
posNum:
mov ah, 02h
mov dl, bl
add dl, 48
int 21h
exit:
mov ah,04ch
int 21h
main ENDP
END main
相关:在 16 位模式下的现代 x86 CPU 上,您可以使用带有范围偏移的 SSE4.1phminposuw
,使其适用于有符号输入。 您可以在一条指令中找到 8 个元素中的最小值:x86 程序集 - 4 个给定数字中的 2 个最大值。 使用pmovsxbw xmm0, [num]
加载有符号字节。
实现最小值查找循环的更有效方法是避免缓慢的loop
指令,并在没有新的最小值时避免采用分支(循环分支除外)。 我本可以通过使用loop
和/或使用正常采用的jge
跳过循环中的指令来缩小代码,而不是陷入通常不运行的代码中。
相关:在数组中查找第二大值的汇编程序。 我在那里使用了类似的循环结构。
与端点指针进行比较是有效的,无论是常量还是在寄存器中。 作为即时,它将指令保存在循环之外。 我们也不需要用循环计数器捆绑CX
;我们已经在SI
中有了指针.
这个答案的要点是用于打印前导-
的更紧凑的代码,就像我在@Ahtisham答案的评论中提到的。 请参阅下面main
的第二部分。
.model small
.stack 100h
.data
num db 0,5,-1,4,2 ;my array
numEnd:
numSize = numEnd - num
msg db "The min number is: $"
.code
main PROC
mov ax, @data
mov ds, ax
mov si, OFFSET num
mov bl, [si] ; bl = min
calMin: ; do {
cmp si, OFFSET numEnd-1
jae endloop ; if (p >= end-1) break;
inc si ; p++
cmp bl, [si]
jle calMin ; if (*p <= min) continue; signed compare
; on new min, fall through and update BL before continuing
mov bl, [si] ; min = *p
jmp calMin ; } while(1);
endloop:
;;; BL = min. Do whatever you want with it.
现在我们有数组的最小值bl
.
通常,您会加载到寄存器中,而不是使用多个加载,但对于大多数输入,mov al, [si]
很少运行。 重新加载相同的值很快(因为缓存),因此在常见情况循环中保存指令是一个胜利,即使这意味着当我们找到新的最小值时需要额外的负载。
给定一个个位数的有符号min
bl
,我们可以打印它(如果它是负数,则用-
):
; we could print the message before the loop
; if we wanted to avoid clobbering registers.
mov ah, 09h ; print a message first
mov dx, offset msg
int 21h ; al = write string to stdout(ds:dx)
mov dl, bl ; in case it's positive
neg bl ; bl = 0 - bl setting flags accordingly
jle posNum ; if (0 <= num) skip the leading '-'
mov ah, 02h
mov dl, '-' ; print minus symbol if negative number
int 21h ; al = print char to stdout(dl)
mov dl, bl ; the negated value is positive, print it
posNum:
; absolute value of single-digit number in DL
mov ah, 02h
add dl, '0'
int 21h ; al = print char to stdout(dl)
exit:
mov ax, 04c00h ; AL = 0 (exit status), AH = 4C (Exit function)
int 21h
main ENDP
END main
您无需使用单独的js
和jz
说明分别测试SF
和ZF
。 如果原始数字为负数,我使用neg
后的jle
,因为它根据0 - num
设置标志。 即 如果0 <= num
,则取jle
,即num
是非负数的,我们不应该打印'-'
。
我本可以做到的
test bl, bl
jge posNum
因为test same,same
设置的标志与cmp bl, 0
相同。 当然,对于大于或等于零的数字,jge
取
。请注意,0 - 128
确实会溢出,因此仅在neg
后测试SF并不等同于jle
。jle
是正确的,js
不是。
但是我们的打印首先只处理个位数的整数。 如果这就是您所拥有的,请在打印可选'-'
后,使用众多多位数函数之一将绝对值打印为无符号整数。