我这里有一小部分计算器代码。我想请求有关如何使用负数执行算术运算的帮助。
这是我的代码:
ASSCII_LOOP : MOV EDX , 0
DIV ECX
OR DL , 30H ;MAKE REMINDER ASSCII
MOV [ESI] , DL ;PUT ASSCII IN ASSCII_NUM
DEC ESI
INC EBP ;ADD ONE TO THE CHAR'S COUNTER
CMP EAX , 0 ;IF AX > 0 GOTO
JA ASSCII_LOOP ;ASSCII_LOOP
CMP EDI , 0 ;CHECK IF THAT WAS A NEGETIVE NUMBER
JZ REST ;IF THATS NOT NEGETIVE GOTO REST
MOV DL , '-'
MOV [ESI] , DL ;ADD A MINES SIGN TO THE STRING
DEC ESI
INC EBP
REST :
LEA EDI , ASSCII_NUM
;MOVE THE ASSCII CODE TO IT'S RIGHT PLCAE IN ASSCII_NUM
ORDER_ASSCII : INC ESI
MOV AL , BYTE PTR [ESI]
MOV BYTE PTR [EDI] , AL
INC EDI
DEC EBP
CMP EBP , 0
JA ORDER_ASSCII
MOV CL , '$'
MOV BYTE PTR [EDI] , CL ;AT LAST PUT A DOLLOR SIGN AT THE END OF ASSCII_NUM
此程序检查输入是否为负,如果为负,则转至REST。我想问下面这个:
*这个程序中REST的功能是什么?
*我想询问有关如何开始在此程序中编写代码以对负数执行操作的建议。我已经知道2'补充的东西,我想要的是2的补码代码,我只是不知道从哪里开始,如何开始。我是装配编程的新手。希望你能帮助我。
这是我尝试过的代码,但它不起作用,为了更好地理解,我单独说出来了:
neg_num:
mov ax, data
mov ds, ax
mov es, ax
mov ah, 0000h
mov al, num
NOT al
mov bl, al
adc al, 00000001B
mov bl, al
答案 0 :(得分:1)
我将向您展示如何实现2&补码以执行简单减法的示例。我将使用我自己的通用助记符来演示如何实现这一点。然后,您可以将其应用于装配程序。
我们将遵循A-B = A +的模型(B(1' s补码)+ 1)
好的,我们可以说我们想从A(A-B)中减去累加器B的内容。
让我们假设我们的累加器A值的操作数已到位([AccA]< -someValue)。
首先:从内存中获取所需的值并将其存储在累加器B中。
MOVM B 'Move contents of memory into Acc B ([AccB]<-someOtherValue)
第二:补充B的值以得到否定
CMPL B 'AccB = -B
第三步:将1的补充值移至某个临时存储寄存器
MOVBR R0 'Move contents of Acc B to Register 0
第四:我们想加载一个&#39; 1&#39;进入现有的蓄能器B
MOVB #1 'Move a '1' immediately to Acc B [AccB]<- 1
第五:我们想将AccB的内容添加到RO,我们的-B存储在
中 ADDB RO ' This takes care of the (B(complement) +1 part of our model)
' The resulting value will be stored in AccB
第六:最后,添加AccA和AccB
ADAB 'Mnemonic for "Add AccA to AccB, result stored in AccA"
这满足了我们对A +(B(补语)+ 1)的要求
这都假设您的架构不允许使用简单的SUBA或SUBB命令。有些处理器内置了这些处理器,但是由于你正在学习它的机制,上面的基本代码结构有希望为你描绘出更好的图像。
答案 1 :(得分:1)
你对此有太多麻烦,疤面煞星! x86不使用1的补码,因此该示例可能有用也可能没用。我们使用2的补码,因为它“正常”(无论如何应该)。你的最新代码应该给你一个2的补码(adc
是不对的),但是neg al
更容易 - 这就是它的作用。
第一个示例的REST
部分只是将您放置在缓冲区“end”的字符移动到缓冲区的“开头”。如果您在正确的位置(esi
)开始打印位置,则根本不需要这样做。
就在您展示的内容之前,您执行了test eax, 8000h
之类的操作来确定数字是否为负数。如果它是否定的,则neg eax
并设置一个标记(edi
)以表示我们想要一个减号。由于你在整个过程中使用32位数字,我会......
test eax, eax
jns is_positive
test eax, eax
jns is_positive
仅测试第15位将适用于16位数字,但您在此处使用的是32位寄存器/指令。混合大小的数字可能会给你带来麻烦。因为你有一个非常好的(未经测试,但我没有看到任何错误)32位数字到ascii例程,提供32位数字。或者,我认为如果你在整个过程中切换到16位寄存器,你的例程仍然可以工作。用'$'终止你的字符串给我一个线索,这可能是16位代码。使用32位数字/寄存器/指令仍然可以工作,但坚持使用一个大小的数字。我觉得你的麻烦会减少。
在您未显示的部分 - 从键盘获取数字 - 如果用户以减号开头,请跳过减号并设置标记。如果标志设置,则将ascii转换为数字,最后转换为或
neg ax
。
neg eax
现在,mov eax, 3
sub eax, 4
mov eax, 3
sub eax, 4
将是负数 - 2的补码 - 只需使用它。如果您希望将其更改为正数,请“翻转”所有位(或
eax
和所有位)并添加1.(这可用于正 - 负或负 - -positive)这就是2的补码是如何工作的,但只有not
才会在一条指令中完成。
如果您需要在保留符号的同时更改数字的大小,xor
左右会这样做,但更容易坚持相同的尺寸,
您的代码中可能存在严重错误,我只是没有看到,但您展示的内容看起来相当不错(neg
部分除外)。我怀疑问题出在其他地方 - 也许混合数字大小......