【发布时间】:2016-02-09 06:58:48
【问题描述】:
为了这个程序的目的,我必须编写一个程序来计算一个 22/21*(r^2)*h 的圆锥体积。
因此,我开发的这段代码适用于在将变量相乘后不会导致 EDX 寄存器被填充的任何变量。我不能将寄存器移位或“或”在一起,也不能使用跳转或 cmp 语句。我还必须将 8 位寄存器用于高度和宽度变量,16 位用于半径^2 和半径^2*高度计算,然后用 32 位完成最后的除法计算。看一看。我不知道为什么它会溢出到 EDX 中,我不知道如何纠正它......
.data
radius WORD ? ;var for radius
height WORD ? ;var for height
numerator WORD 22 ;Making a variable for numerator
denominator DWORD 21 ;Making a variable for denominator
volume DWORD ? ;Making a variable to store volume main
decimal DWORD ? ;Making a variable to store volume remainder
prompt BYTE "Enter the radius: ",0 ;val for radius prompt
promp2 BYTE "Enter the height: ",0 ;val for height prompt
result BYTE "The volume of the cone is: ", 0 ;val for printing volume
decim BYTE ".", 0 ;val for decimal place
;volume of cone is 1/3(pi(r^2)h) or 22/21(r^2)h
.code
main PROC
mov edx,OFFSET promp2 ;move prompt into edx for printing
call WriteString ;ask user for height
mov eax,0
mov edx,0
mov ecx,0
mov ebx,0 ;move zero into all main registers
call ReadDec ;reading the height
mov bl,al ;move height into storage
mov edx,OFFSET prompt ;move promp2 into edx for printing
mov eax,0 ;re-zero eax
call WriteString ;ask user for radius
call ReadDec
mul al ;obtain r^2
mul bl ;multiply r^2 by height
mov edx,0 ;zero out edx
mov dx,numerator ;move numerator into dx
mul dx ;multiply r^2*h by 22
mov ebx,denominator ;move 21 into ebx to divide
div ebx ;divide by 21 to get total volume
mov volume,eax ;move volume into volume variable
mov decimal,edx ;move decimal remainder into decimal variable
mov edx,OFFSET result ;prepare string result for printing
call WriteString ;print result string
mov eax,volume ;move volume into eax to print
call WriteDec ;print volume
mov edx,OFFSET decim ;move dec into print register
call WriteString ;print decimal
mov eax,decimal ;move decimal remainder into eax to print
call WriteDec ;print decimal value
call CRLF ;carriage return and new line
call WaitMsg ;pause output
exit
main ENDP
也许我可以为中间算术做不同的寄存器,但鉴于当前的 8-8-16-16-32 要求,我不知道如何实现。如果有人可以帮助我提供一个可行的解决方案并解释它为什么起作用,也许可以逐步完成它,这样我就可以理解为什么我的不适用于更大的整数(大多数超过 20 不起作用),这将是惊人的。提前感谢您能给我的任何帮助!
【问题讨论】:
-
如果您的问题是在您进行除法时
edx不为零,那么解决方案是清除它:mov edx, 0(或xor edx, edx)。跨度> -
edx 存储乘法运算产生的 16 到 32 位溢出以及除法运算的余数。在将“分子”移入其中以执行 AX 和 DX 之间的 16 位乘法之前,我清除了 edx。比如运行这个程序,分别插入18和15。将 AX 和 DX 相乘后,EAX 的前两个字节被填充,剩下的字节进入 DX,应该使用 shl EDX,16 然后或 EAX,EDX 将其移动到 EAX 的头部,但我不能这样做,因为它是对程序的限制。
-
div ebx将edx:eax中的64 位值除以ebx。您的乘法结果在dx:ax中。您要么需要使用在相同寄存器对上操作的mul和div的变体,要么通过在除法之前清除edx来丢弃乘法溢出。 -
但是如果我清除乘法溢出,它会给出一个不正确的答案,因为正确答案的十六进制值将会改变。我认为从 EBX 切换到 BX 可以解决它,它解决了溢出问题,但现在它只划分 AX 寄存器中的内容,而不是 DX:AX 的组合。
-
那么为什么不乘以一个 32 位寄存器(例如
mul edx),这样乘积最终会出现在edx:eax中?
标签: assembly nasm integer-overflow irvine32