简体   繁体   English

在数组中查找最小值(Intel8086)

[英]Finding the minimum in an array (Intel8086)

I'd like to write a simple program to find the minimum value in an array . 我想编写一个简单的程序来查找数组中最小值 I'm using Intel 8086 architecture (if I'm right?). 我使用的是Intel 8086架构(如果我是对的?)。 The problem is that I am totally new to Assembly language and well, I just cannot figure out what am I doing wrong in my code, I'm stuck. 问题是我对汇编语言完全陌生,好吧,我只是无法弄清楚我在代码中做错了什么,被卡住了。

At the end (before exiting) my ax register does not contain my result. 最后(退出之前),我的ax寄存器不包含我的结果。
I'm afraid it doesn't even place it there (I check registers' values with Turbo Debugger tool). 恐怕它甚至都不会放在那儿(我用Turbo Debugger工具检查寄存器的值)。

.MODEL TINY

Data SEGMENT
                        arr_len     EQU 5
                        arr         DB 07h, 02h, 03h, 10h, 12h
                        minimum     DB 255
Data ENDS

Code SEGMENT
                        ORG 100h
                        ASSUME CS:Code, DS:Data, SS:Code
Start:
                        mov ax, SEG Data
                        mov ds, ax  ;load data to ds reg    
                        mov cx, arr_len ;arr_length to counter
                        mov bx, OFFSET arr ;load first elem.
Search: 
                        inc bx
                        cmp bl, [minimum] ;compare loaded elem with min
                        jb Swap ;if bl<minimum
Swap:
                        mov minimum, bl
                        loop Search         

                        mov al, minimum ;result here?
                        mov ax, 4C00h
                        int 21h

Code ENDS
END Start

Could anyone give me advices what is wrong here? 谁能给我建议这里出了什么问题? Thanks in advance. 提前致谢。

  • The tiny model doesn't need setting DS explicitly. 小型模型不需要显式设置DS。 (CS=DS=ES=SS) (CS = DS = ES = SS)
  • Since BX points at your array the first time, you should not immediately increment it! 由于BX第一次指向阵列,因此您不应该立即对其进行递增! Do inc before looping only. 仅在循环之前执行inc
  • You didn't really compare an array element but rather the low byte of the address by which you iterate the array. 您实际上并不是比较数组元素,而是比较数组的地址的低字节。
  • There's no sense in putting any result in AL if directly afterwards you exit by putting 4C00h in AX. 如果您随后直接通过将4C00h放入AX退出,则在AL中放入任何结果都没有意义。 Viewing AL using a debugger could work though. 但是,使用调试器查看AL可能会起作用。

Here's a version that can work: 这是可以使用的版本:

Search: 
    mov al, [bx]
    cmp al, [minimum] ;compare loaded elem with min
    jnb NoSwap        ;if al>=minimum
    mov [minimum], al ;New minimum
NoSwap:
    inc bx
    loop Search

Like Fifoernik's answer explained, your conditional branch jumps to the same place whether it's taken or not, because the branch target is the next insn. 就像Fifoernik的答案所解释的那样,无论是否采用条件分支,您的条件分支都会跳转到同一位置,因为分支目标是下一个insn。


Here's how to do it without keeping your minimum in memory as you accumulate it, because that's horrible. 这是在不累积minimum内存的情况下执行此操作的方法,因为这太可怕了。

This version accumulates minimum in al , never storing it to memory. 此版本累积的minimumal ,永远不会将其存储到内存中。 I also used string ops for fun. 我还使用了字符串操作来娱乐。 You'll get smaller code size, but maybe slower code than loading with mov . 您将获得较小的代码大小,但与使用mov加载相比,代码可能会更慢。 Using si as a source pointer is a good convention to help humans keep track of things, even when not using string ops. 使用si作为源指针是一个很好的约定,即使没有使用字符串操作,也可以帮助人们跟踪事物。 Don't make the code worse just for that, of course, but I recommend it when you have the choice. 当然,不要为此而使代码变糟,但是我建议您在有选择的情况下使用它。

I also avoid loop because it's slow and wasn't gaining us much of anything . 我还避免loop因为它很慢并且没有为我们带来任何好处 Unless you're going hard-core optimizing for code-size over speed, don't use loop . 除非您要对速度进行代码大小的硬性优化,否则请不要使用loop

.MODEL TINY
Data SEGMENT
    arr         DB 07h, 02h, 03h, 10h, 12h
    arr_len     EQU $-arr                   ; let the assembler calculate the size to avoid mistakes
Data ENDS

Code SEGMENT
    ORG 100h
    ASSUME CS:Code, DS:Data, SS:Code
unsigned_min:
    ;; segment setup not needed with tiny model, according to Fifoernik
    ; assume arr_len >= 2
    mov    si, OFFSET arr       ; src pointer = &first element
    lea    di, [si + arr_len]   ; end pointer.
    ;; mov di, arr_len + OFFSET arr ; also works, since input pointer is static
    ;; or use arr_len + OFFSET arr as an immediate operand for the loop condition, if you don't care about keeping the hard-coded input address out of the loop itself.

    cld                         ; clear the direction flag so string insns count upwards.  Omit if the ABI guarantees this state already
    lodsb                       ; al = min so far = first element, and advance si to point to the second element


;; on entry: AL = 1st element (min).  SI = pointer to 2nd element.  DI = end-pointer
Search:
    cmpsb                       ; compare [si] with current min (al), and ++si
    jae   .no_new_min

    mov    al, [si-1]           ; conditionally skipped.  You could use `cmov` instead of the branch on a CPU supporting 686 insns
.no_new_min
    cmp    si, di               ; loop while si < end
    jb    Search

    ; min is in AL

    mov ah, 4Ch            ; exit with AL as exit status
    int 21h

If you can't assume arr_len >= 2 , then initialize min to 255 or the first element, and enter the loop with it pointing to the first element, instead of 2nd. 如果不能假定arr_len >= 2 ,则将min初始化为255或第一个元素,然后输入指向第一个元素而不是2nd的循环。 Or use an extra cmp si,di / jb outside the loop. 或在循环外使用额外的cmp si,di / jb

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM