程序求解方程式

时间:2015-06-04 13:49:57

标签: assembly equation tasm dosbox operands

我的汇编中的简单程序有问题。我正在使用DOSbox和TASM。我有程序问题。操作数类型与第76 78 80行不匹配。这是在乘法之后。我尝试使用difftrent变量

进行一些更改
; --------------------------------------------
; 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

2 个答案:

答案 0 :(得分:3)

你的程序几乎是好的,你只有操作数大小的一些问题,这是正常的。所以我接受了你的代码并进行了一些小改动,这些更改被注释并用箭头指示(< ========),它们是:

  • 修复了操作数大小问题。我仍然使用数据库,因为我注意到你将这些数字作为单个字符捕获。
  • (d-2 * c)的结果存储在BX中。这是因为我们需要划分(a + c * b)/(d-2 * c),并且你在BX中弹出(a + c * b),所以,当你执行var pack = d3.layout.pack() .size([500,400]) .value(function(d) { return d.size; }); 时你正在做(d-2 * c)/(a + c * b)。
  • 将商和剩余部分分开显示。
  • 为邮件添加了div bx换行符。
  • 13,10修正了shl ax,2。一个shl ax,1是x2,两个shl是x2x2。
  • 剩余部分来自shl,因为当dl使用单词作为除数时,其余部分保留在div

这是您的代码,稍有变化(在EMU8086上测试):

dx

接下来是你要做的事情"列表:

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

Assembly x86 Date to Number - Breaking a string into smaller sections

32 bit Calculator in 8086 Assembly

最后,测试数据:

; --------------------------------------------
; 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

答案 1 :(得分: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 变量定义为字节,您不能通过 word 大小的寄存器 AX 合法地使用它们。这就是 TASM 给您错误消息的原因。

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

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

冗余括号我们得到的一切:(a+c*b)/d-2*c <=> ((a+(c*b))/d)-(2*c)

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

考虑到 abc 是从 0 到 9 的个位数,并且 d 是从 1 到 9 的一位数,结果的范围可以从 -18 到 72。因此我们可以使用字节大小的操作来计算整个表达式。没有必要使用带符号的除法 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) 来查找结果。你会预料到这一点吗?

以下是我对这一切的实现。我只省略了显示商和余数的部分,但我提供了一个链接 Displaying numbers with 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, "? = $"