4

我在汇编中的简单程序有问题。我正在使用 DOSBox 和 TASM。问题是第 76、78 和 80 行中的操作数类型不匹配。这是在乘法之后。我试图通过使用不同的可变大小来进行一些更改。

; --------------------------------------------
; Equation=(a+c*b)/d-2*c,
; --------------------------------------------
.model small
.stack 100h
.data
        a       db 0                           
        b       db 0
        c       db 0
        d       db 0
        result1 db ?
        result2 db ?
       
 
       
        message1 db "Equation: (a+c*b)/d-2*c   a=$"
        message2 db "b=$"
        message3 db "c=$"
        message4 db "d=$"
        message5 db "Result=$"
.code
 
start:  mov ax,@data
                mov ds,ax                      

                mov ax, seg message1   ;get a and save to a variable
                mov ds,ax      
                mov dx,offset message1
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h    ;converting to real number
                mov a,al
               
                mov ax, seg message2 ;get b and save to a variable
                mov ds,ax      
                mov dx,offset message2
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h    ;converting to real number
                mov b,al
               
               
                mov ax, seg message3    ;get c and save to a variable
                mov ds,ax      
                mov dx,offset message3
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h    ;converting to real number
                mov c,al
               
            
                mov ax, seg message4   ;get d and save to a variable
                mov ds,ax      
                mov dx,offset message4
                mov ah, 9h
                int 21h
                mov ah, 1h
                int 21h
                sub al,30h   ;converting to real number
                mov d,al
               
               
                mov al,b         ; (a+c*b) ------------------------error
                mul c                          
                add ax,a       ; ------------------------error
       
                push ax     ;save current ax
       
                mov ax,c     ;d-2*c------------------------error
                shl ax,2
                sub d,ax
               
               
                pop bx     ;get previous ax  to bx
               
                div bx     ; div ax:bx
               
                mov result1,al
                mov result2,ah
       
                add result1,30h   ;converting to string
                add result2,30h    ;converting to string
               
                mov al,result1
                mov bl,result2
               
                mov ax, seg message5
                mov ds,ax      
                mov dx,offset message5
                mov ah, 9h
                int 21h
                mov al,result1
                mov bl,result2
                mov dl, al
                mov ah , 2h
                int 21h
                mov dl, bl
                mov ah , 2h
                int 21h
               
                mov ax,4C00h           
                int 21h
 
end             start
4

2 回答 2

2

您的程序几乎很好,您只有操作数大小有一些问题,这是正常的。因此,我采用了您的代码并进行了一些小改动,这些更改由箭头(<========)注释和指出,它们是:

  • 修复了操作数大小问题。我仍然使用 DB,因为我注意到您将数字捕获为单个字符。
  • (d-2*c) 的结果存储在 BX 中。这是因为我们需要除 (a+c*b) / (d-2*c),而你在 BX 中弹出 (a+c*b),所以,当你这样做时,div bx你正在做 (d-2* c) / (a+c*b) 。
  • 分开显示商和余数。
  • 在消息中添加13,10了换行符。
  • shl ax,2由固定shl ax,1。一个shl是 x2,两个shl是 x2x2。
  • 余数取自 ,dl因为当div使用一个词作为除数时,余数留在 中dx

这是您的代码稍作改动(在 EMU8086 上测试):

; --------------------------------------------
; Equation=(a+c*b)/d-2*c,
; --------------------------------------------.model small
.stack 100h
.data
    a   db 0                
    b   db 0
    c   db 0
    d   db 0
    result1 db ?
    result2 db ?



    message1 db 13,10,"Equation: (a+c*b)/d-2*c",13,10,"a=$"
    message2 db 13,10,"b=$"         ;<================= 13,10 IS
    message3 db 13,10,"c=$"         ;<================= LINEBREAK.
    message4 db 13,10,"d=$"         ;<=================
    message5 db 13,10,"Quotient=$"  ;<=================
    message6 db 13,10,"Remainder=$" ;<=================
.code

start:  mov ax,@data
        mov ds,ax           



        mov ax, seg message1   ;get a and save to a variable
        mov ds,ax   
        mov dx,offset message1
        mov ah, 9h
        int 21h
        mov ah, 1h 
        int 21h
        sub al,30h    ;converting to real number
        mov a,al

        mov ax, seg message2 ;get b and save to a variable
        mov ds,ax   
        mov dx,offset message2
        mov ah, 9h
        int 21h
        mov ah, 1h
        int 21h
        sub al,30h    ;converting to real number
        mov b,al


        mov ax, seg message3    ;get c and save to a variable
        mov ds,ax   
        mov dx,offset message3
        mov ah, 9h
        int 21h
        mov ah, 1h 
        int 21h
        sub al,30h    ;converting to real number
        mov c,al


        mov ax, seg message4   ;get d and save to a variable
        mov ds,ax   
        mov dx,offset message4
        mov ah, 9h
        int 21h
        mov ah, 1h 
        int 21h
        sub al,30h   ;converting to real number
        mov d,al


        mov al,b          ; (a+c*b)
        mul c
        mov cl,A    ;<======== MOV A TO CX TO
        mov ch,0    ;<======== ADD IT TO AX.
        add ax,CX   ;<======== C*B + A.

       ;push ax     ;<======== NO LONGER NECESSARY BECAUSE
                    ;<======== IN NEXT BLOCK WE USE BX.

        mov bl,C    ;<======== MOV C TO BL AND CLEAR
        mov bh,0    ;<======== BH. NOW C IS IN BX.
        shl bx,1    ;<======== 2*c. ONE SHIFT IS x2, TWO SHIFTS ARE x2x2.
        sub d,bl          ;d - 2c
        mov bl,d    ;<======== MOV D TO BL AND CLEAR BH. NOW
        mov bh,0    ;<======== D IS IN BX. BX = (D-2C).

       ;pop ax      ;<======== NO LONGER NECESSARY. AX CONTAINS (A+C*B).

        mov dx,0    ;<======== CLEAR DX, BECAUSE DIVISOR IS A WORD.
                    ;<======== WHEN DIVISOR IS A WORD, DIV USES DX:AX. 
        div bx      ;<======== dx:ax / bx == DX:(A+C*B) / (D-2C). THIS
                    ;<======== DIVISION IS UNSIGNED, FOR SIGNED USE IDIV.

        mov result1,al ;<===== QUOTIENT.
        mov result2,dl ;<===== REMAINDER, BECAUSE DIVISOR IS WORD.

        add result1,30h   ;converting to string
        add result2,30h    ;converting to string

        mov al,result1
        mov bl,result2

      ;DISPLAY QUOTIENT  <=============
        mov ax, seg message5
        mov ds,ax   
        mov dx,offset message5
        mov ah, 9h
        int 21h
        mov al,result1
        mov dl, al
        mov ah , 2h
        int 21h       
      ;DISPLAY REMAINDER  <=============
        mov ax, seg message6
        mov ds,ax   
        mov dx,offset message6
        mov ah, 9h
        int 21h
        mov dl, bl
        mov ah , 2h
        int 21h

        mov ax,4C00h        
        int 21h

end     start

接下来是您的“待办事项”清单:

  • 将操作数的大小从 DB 更改为 DW,以允许您的程序处理更大的数字。
  • 将 DIV 更改为 IDIV,因为 DIV 未签名而 IDIV 已签名。IDIV 将让您处理负面结果。
  • 将 int=21h ah=0Ah 的数字捕获为字符串(而不是单个字符)。稍后,您将字符串转换为数字。接下来的两个链接将带您了解从字符串转换为数字的过程:

Assembly x86 Date to Number - 将字符串分成更小的部分

8086 汇编中的 32 位计算器

最后,测试数据:

(a+c*b) / (d-2*c)

a=1
b=2
c=3
d=8

a+c*b = 1+3*2 = 7
d-2*c = 8-2*3 = 2

7 / 2 = quotient 3, remainder 1
于 2015-06-04T15:20:00.213 回答
1

因为这个问题在 9k 浏览量上取得了巨大的成功,并且因为接受的答案本质上是错误的和误导性的,所以我决定发布一个正确的版本,以便人们最终找出如何计算这些简单的表达式。


我的程序有问题。操作数类型在第 76 78 80 行不匹配。

add  ax,a   ; line 76
push ax
mov  ax,c   ; line 78    
shl  ax,2
sub  d,ax   ; line 80

在大多数汇编指令中,逗号两边的操作数的大小必须匹配。由于您已将abcd变量定义为字节,因此您不能合法地将它们与大小的寄存器一起使用AX。这就是 TASM 给您错误消息的原因。

在评估类似 的表达式时(a+c*b)/d-2*c,您必须遵守代数规则。

  • 括号内的项目作为一个整体计算
  • 对于没有括号的项目,您需要遵循正常的优先级规则:*and /come before +and-

对我们得到的所有内容进行冗余括号:(a+c*b)/d-2*c<=>((a+(c*b))/d)-(2*c)

  • 当括号集嵌套时,内部集优先于外部集

考虑到abc是从 0 到 9 的单个数字,而d是从 1 到 9 的单个数字,结果的范围可以从 -18 到 72。因此我们可以使用 byte- 来计算整个表达式规模的操作。没有必要使用带符号的除法idiv,因为此时的股息将始终为正。

mov  al, c    ; AL = c
mul  b        ; AL = c * b                           AH is 0
add  al, a    ; AL = (c * b) + a                     AH is 0
div  d        ; AL = ((c * b) + a) / d               AH is remainder
sub  al, c    ; AL = (((c * b) + a) / d) - c         AH is remainder
sub  al, c    ; AL = ((((c * b) + a) / d) - c) - c   AH is remainder

请注意,我们只使用了一个寄存器 ( AX) 来查找结果。你会预料到这一点吗?

下面是我对这一切的实现。我只省略了显示商和余数的部分,但我提供了 使用 DOS 显示数字的链接,该链接非常详细地解释了如何输出有符号和无符号数字。这是您必须知道的基本内容,因此如果您通读它,绝不会浪费时间。

; --------------------------------------------
; Expression=(a+c*b)/d-2*c,
; --------------------------------------------
  ORG  256              ; Use the .COM file format

; Make sure all inputs are valid single digit numbers                      
  cld
  mov  dx, offset msgA
  mov  ah, 09h          ; DOS.PrintString
  int  21h
  mov  di, offset a     ; Storage for the a, b, c, and d variables (adjacent in memory)
  mov  si, offset msgB  ; Offset of the incomplete message
  mov  bl, "a"          ; Character that completes the message
Again:
  mov  [si+2], bl       ; Completing the message
  inc  bl
  mov  dx, si
  mov  ah, 09h          ; DOS.PrintString
  int  21h
Redo:
  mov  ah, 01h          ; DOS.GetCharacter
  int  21h              ; -> AL
  sub  al, 30h          ; From character ["0","9"] to number [0,9]
  cmp  al, 10
  jnb  Redo
  stosb                 ; Is indeed in range [0,9]
  cmp  bl, "e"          ; Repeat for "b", "c", and "d"
  jb   Again
  dec  di
  cmp  al, 0
  je   Redo             ; Can't allow d=0 since it will be used as a divider

; The calculation
  mov  al, c            ; AL = c
  mul  b                ; AL = c * b                           AH is 0
  add  al, a            ; AL = (c * b) + a                     AH is 0
  div  d                ; AL = ((c * b) + a) / d               AH is remainder
  sub  al, c            ; AL = (((c * b) + a) / d) - c         AH is remainder
  sub  al, c            ; AL = ((((c * b) + a) / d) - c) - c   AH is remainder
  mov  Q, ax            ; Storage for the Q, and R variables (adjacent in memory)

; Displaying the quotient and remainder
  mov  dx, offset msgB  ; Offset of the incomplete message
  mov  ax, 0951h        ; DOS.PrintString
  mov  [msgB + 2], al   ; Completing the message with AL = "Q"
  int  21h
  mov  al, Q
  call DisplaySignedNumber8

  mov  dx, offset msgB  ; Offset of the incomplete message
  mov  ax, 0952h        ; DOS.PrintString
  mov  [msgB + 2], al   ; Completing the message with AL = "R"
  int  21h
  mov  al, R
  call DisplaySignedNumber8

  mov  ax, 4C00h        ; DOS.Terminate
  int  21h
; --------------------------------
a    db 0                           
b    db 0
c    db 0
d    db 0
Q    db 0
R    db 0
msgA db "Formula: (a+c*b)/d-2*c$"
msgB db 13, 10, "? = $"
于 2020-12-27T15:35:37.210 回答