Assembly 装配方程,除以以获得浮点值

Assembly 装配方程,除以以获得浮点值,assembly,floating-point,x86,x86-16,tasm,Assembly,Floating Point,X86,X86 16,Tasm,我必须在汇编中做这个等式(3*a-b/a)*(d+3),我在除以b/a(10/20)时遇到问题,结果应该是0.5,但我得到0。我真的不知道我该怎么做。我的任务是修复给定代码中的语法和逻辑错误: ;=============================================================================; ;

我必须在汇编中做这个等式
(3*a-b/a)*(d+3)
,我在除以b/a(10/20)时遇到问题,结果应该是0.5,但我得到0。我真的不知道我该怎么做。我的任务是修复给定代码中的语法和逻辑错误:

;=============================================================================;
;                                                                             ;
; File           : arch1-2e.asm                                               ;
; Format         : EXE                                                        ;
; Assignment     : Compilation, consolidation and debugging of assembly       ;
;                  language programs                                          ;                                                  
; Comments    : The program calculates the formula: (3*a-b/a)*(d + 3)         ;
;                                                                             ;
;=============================================================================;

                .MODEL: SMAL

Stos            SEG

a               DB      20
b               =       10
c               EQU     3
Wynik           DB      ?

ENDSEG          Dane

Kod             SEG

                ASJUM   CS:Start, DS:, SS:Stos

d               DW      5

Start:
                mov     ax, ds
                mov     ax, SEG Kod

                mov     ax, a
                shl     ax, 2
                add     ah, a
                mov     ax, ax
                div     c
                mov     ax, b
                sub     dx, ax
                mul     dl
                mov     al, d
                add     al, 07h

                mov     ax, WORD PTR Wynik

                mov     ax, 4C5h
                ind     21h

Dane            ENDSEG

Stosik          SEGM    SACK

                DB      100h DOOP [?]

Kod             ENDSEG

                END     Stop
我尝试修复此代码是:

.MODEL SMALL
  a               EQU     20
  b               EQU     10
  c               EQU     3
  d               EQU     5

Dane            SEGMENT
  Wynik          DB      ?
Dane Ends

Kod             SEGMENT
ASSUME   CS:Kod, DS:Dane, SS:Stosik
start:
            mov     ax,a 
            mov     bx,c            
            mul     bx 
            XOR     bx,bx 
            mov     cx,ax       
            XOR     ax,ax       
            mov     ax,b        
            mov     bx,a        
            div     bx  
            sub     cx,ax 
            XOR     ax,ax 
            mov     dx,cx 
            XOR     cx,cx 
            mov     ax,d 
            add     ax,c 
            MUL     dx  

            mov     ax, 4C00h
            int     21h

Kod            ENDS

Stosik      SEGMENT STACK
            DB      100h DUP (?)
Stosik              ENDS
END     start

在不偏离我所认为的准则意图以及我对要求的解释的情况下,我建议如下:

                .MODEL SMALL          ; I Assume we are producing EXE program

c               EQU     3             ; 3 is a constant in the equation

Dane            SEGMENT 'DATA'
a               DW      20            ; a, b, d are variables in the equation
b               DW      10            ;     so treat them as variables
d               DW      5             ; All these variables should be DW
Wynik           DW      ?

Dane ENDS

Kod             SEGMENT 'CODE'
                ASSUME  CS:Kod, DS:Dane, SS:Stosik

Start:
                mov     ax, SEG Dane  ; For EXE we need to set DS
                mov     ds, ax        ;     To Dane segment manually

                mov     ax, a         ; Multiplying a by 3 is the same
                                      ;     as multiplying a by 2 and adding a
                shl     ax, 1         ; Multiply a*2
                add     ax, a         ; Add a to previous result in a
                mov     cx, ax        ; Copy result of a*3 to CX
                mov     ax, b         ; Do div b/a
                xor     dx, dx        ; We need to ensure DX is zerofor this div
                                      ;     as Div is result of DX:AX by a
                div     a
                sub     cx, ax        ; Subtract reslt of b/a from result of a*3
                mov     ax, d         ; ax = d + 3
                add     ax, c
                mul     cx            ; Multiple d+3 (AX) by a*3-b/a (cx)

                mov     Wynik, ax     ; Save 16-bit result in memory

                mov     ax, 4C05h     ; Exit with value 5
                int     21h

Kod            ENDS

Stosik          SEGMENT    STACK

                DB      100h DUP (?)

Stosik          ENDS

                END
该程序保持了原程序的精神,修复了语法和逻辑错误。b/a仍然使用整数除法(你必须向助教或教授询问这一点),它将把结果四舍五入到最接近的整数(如果是10/20,则为0)。此代码中的主要问题是:

  • 有些代码放错了位置
  • 您的
    div
    是DX:AX除以16位值,因此我们需要将DX归零
  • 在一些地方,登记册的名称被更改了
  • 在此代码中,3*a表示为a*2+a=3a。乘以2等于将值左移1

如果教授仍然需要使用整数除法来更好地逼近结果,那么Jester建议将方程重新排列为3*a*(d+3)-(b*(d+3))/a是一个很好的建议。这会将除法延迟到整数除法的四舍五入对结果的影响较小的点,因此最终结果应该只差近1。使用此修订公式的代码如下所示:

            mov     ax, SEG Dane  ; For EXE we need to set DS
            mov     ds, ax        ;     To Dane segment manually

            mov     cx, a
            shl     cx, 1
            add     cx, a         ; cx = 2*a+a = a*3
            mov     ax, d
            add     ax, c         ; ax = d+c = d+3
            mov     bx, ax        ; bx = copy of d+3
            mul     cx
            mov     si, ax        ; si = a*3*(d+3)
            mov     ax, bx
            mul     b             ; ax = b*(d+3)
            xor     dx, dx        ; Avoid division overflow, set DX=0
            div     a             ; ax = b*(d+3)/a
            sub     si, ax        ; si = a*3*(d+3) - b*(d+3)/a
            mov     Wynik, si     ; Save 16-bit result in memory
                mov     ax, SEG Dane  ; For EXE we need to set DS
                mov     ds, ax        ;     To Dane segment manually

                mov     cx, a
                shl     cx, 1
                add     cx, a         ; cx = a*3
                mov     ax, d
                add     ax, c         ; ax = d+c = d+3
                mov     bx, ax        ; bx = copy of d+3
                mul     cx
                mov     si, ax        ; si = a*3*(d+3)
                mov     ax, bx
                mul     b             ; ax = b*(d+3)
                xor     dx, dx        ; Avoid division overflow, set DX=0
                div     a             ; ax = b*(d+3)/a

                shl dx, 1             ; Remainder(DX) = Remainder(DX) * 2
                cmp dx, a             ; Ajustment of whole nuber needed?
                jb .noadjust          ; No? Then skip adjust
                add ax, 1             ;    Else we add 1 to quotient
.noadjust:
                sub si, ax            ; si = a*3*(d+3) - b*(d+3)/a
                mov Wynik, si         ; Save 16-bit result in memory

                mov     ax, 4C05h     ; Exit with value 5
                int     21h
这种变化可能会有轻微的改善。当整数除法产生一个结果时,它将向下舍入到最接近的整数。如果你除以99/100,你将得到0和
div
以及99的余数。答案更接近于1而不是0。通常情况下,当某个值大于等于0.5时,您将向上取整,向下取整小于0.5。如果需要,可以使用
div
中的余数(DX)将最终结果向上调整1或保持结果不变。修订后的代码可能看起来像:

            mov     ax, SEG Dane  ; For EXE we need to set DS
            mov     ds, ax        ;     To Dane segment manually

            mov     cx, a
            shl     cx, 1
            add     cx, a         ; cx = 2*a+a = a*3
            mov     ax, d
            add     ax, c         ; ax = d+c = d+3
            mov     bx, ax        ; bx = copy of d+3
            mul     cx
            mov     si, ax        ; si = a*3*(d+3)
            mov     ax, bx
            mul     b             ; ax = b*(d+3)
            xor     dx, dx        ; Avoid division overflow, set DX=0
            div     a             ; ax = b*(d+3)/a
            sub     si, ax        ; si = a*3*(d+3) - b*(d+3)/a
            mov     Wynik, si     ; Save 16-bit result in memory
                mov     ax, SEG Dane  ; For EXE we need to set DS
                mov     ds, ax        ;     To Dane segment manually

                mov     cx, a
                shl     cx, 1
                add     cx, a         ; cx = a*3
                mov     ax, d
                add     ax, c         ; ax = d+c = d+3
                mov     bx, ax        ; bx = copy of d+3
                mul     cx
                mov     si, ax        ; si = a*3*(d+3)
                mov     ax, bx
                mul     b             ; ax = b*(d+3)
                xor     dx, dx        ; Avoid division overflow, set DX=0
                div     a             ; ax = b*(d+3)/a

                shl dx, 1             ; Remainder(DX) = Remainder(DX) * 2
                cmp dx, a             ; Ajustment of whole nuber needed?
                jb .noadjust          ; No? Then skip adjust
                add ax, 1             ;    Else we add 1 to quotient
.noadjust:
                sub si, ax            ; si = a*3*(d+3) - b*(d+3)/a
                mov Wynik, si         ; Save 16-bit result in memory

                mov     ax, 4C05h     ; Exit with value 5
                int     21h
调整基于中的方法。基本上,如果余数(DX)乘以2小于除数
a
,则无需调整,否则商(AX)需要增加1



第一个版本的结果将是480。第二个结果是476。第二个将更接近预期值。在这种情况下,476的结果恰好是准确的。(3*20-10/20)*(5+3)=59.5*8=476。

如果您想进行组装,并且正在使用旧版本的MASM或TASM来cpile,那么您需要使用x87 FPU指令,如
fdiv
fmul
fadd
fsub
等。注意,您可以重新排列等式,以便使用整数算术。@LưuV nhPhúc:不要说“必须“当它不是严格正确的时候:P定点在这里可以工作,并且只需要一个小数位就可以达到完全的精度,因为小数部分是
1/2
,如果您从未接触过浮点数,那么我建议您非常仔细地重新阅读您的作业。很可能你根本不需要担心它们,数学运算应该是在整数空间中进行的——就你在这里展示的编码级别而言,这听起来恰到好处。因为代码使用的是整数算术,我假设你需要对运算进行重新排序,以便给出正确的结果。这意味着执行
3*a*(d+3)-(b*(d+3))/a
,这样就没有分数了。您可能不希望使用浮点重写它。