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)。此代码中的主要问题是:
- 有些代码放错了位置
- 您的
是DX:AX除以16位值,因此我们需要将DX归零div
- 在一些地方,登记册的名称被更改了
- 在此代码中,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
,这样就没有分数了。您可能不希望使用浮点重写它。