为什么我的程序只能使用pos或neg数字?

时间:2018-11-14 23:49:24

标签: assembly x86 division fasm

我需要编写一个除数程序,该程序使用2个十进制数字(它们可以是正数或负数)并以二进制代码显示答案。

程序正在运行,但只能使用pos或neg数字。当我评论负数时(在NeNegSum下,我标记了它),它与负数和未评论的pos一起使用。我需要做的是使其与所有数字一起使用??

include 'win32ax.inc'
include 'input.inc'

.data
    num1 dd 0 
    num2 dd 0
    mes rb 100h
    Flag db 0
.code

start:
  input_dialog
  or eax, eax
  jz exit
  mov esi, eax
  call ASCIIToNum
  cmp [Flag],1
  jne .NeNeg
  ;neg eax
  mov [Flag],0
  .NeNeg:
  mov [num1], eax

  input_dialog
  ;mov ecx, 3
  or eax, eax
  jz exit
  mov esi, eax
  call ASCIIToNum
  cmp [Flag],1
  jne .NeNeg2
  ;neg eax
  mov [Flag],0
  .NeNeg2:
  mov [num2], eax
  div [num1]
  mov ebx,2

  lea esi, [mes+50]
  cmp eax,0
  jl .NeNegSumm
  neg eax
  mov [Flag],0
  .NeNegSumm:
  ;neg eax  ;<———this neg
  call NumToASCII
  cmp [Flag],1
  jne .Cout
  dec esi
  mov byte [esi],'-'
  .Cout:
  invoke  MessageBox, HWND_DESKTOP, esi, "Div is:", MB_OK
exit:
  invoke  ExitProcess,0
.end start

.input_resources

proc ASCIIToNum 
;local sum2 dd 0
  push ebx ecx
  xor eax,eax 
  xor ebx,ebx
  mov ecx, 10
  jmp .next
.next1:
  mov [Flag],1
  ;inc esi
.next: 
  mov bl, [esi]
  inc esi
  cmp bl,'-'
  je .next1

  cmp bl, ''
  or bl,bl 
  jz .done 
  sub bl, 30h 
  mul ecx 
  add eax,ebx 
  jmp .next 
.done: 
  pop ecx ebx
  ret
endp 

proc NumToASCII
;.sum2 rb 100
  push ecx edx
  mov byte [esi], 0 
  mov  ecx,2
.divloop:
  mov  edx, 0
  div  ecx
  add  dl, 30h
  dec  esi
  mov  [esi], dl
  or  eax, eax
  jnz  .divloop
  pop edx ecx  
  ret
endp

1 个答案:

答案 0 :(得分:1)

您正在使用DIV指令来计算num2 / num1DIV用于除无符号数字。如果您需要除以带符号的数字(正数和负数),请使用IDIV指令。

由于IDIV [num1]实际上执行EDX:EAX / [num1],因此请不要忘记提前分配分红。 (cdq将EAX符号扩展为EDX:EAX,即将EDX的所有位设置为EAX的符号位。)

该除法的商已经是一个带符号的数字。要决定输出“-”字符,只需查看EAX中数字的符号。

其他评论:

。将与符号相关的指令移至 ASCIIToNum 转换例程更有意义。

。转换为二进制表示形式时,不应使用2除(效率极低)。只需向右移动即可轻松实现。

。您可以编写此代码,而无需单独的 Flag 变量。而是保存并还原处理器标志。

include 'win32ax.inc'
include 'input.inc'

.data
    num1 dd 0 
    num2 dd 0
    mes  rb 100h
.code

start:
  input_dialog
  test eax, eax
  jz   exit
  mov  esi, eax
  call ASCIIToNum
  mov  [num1], eax

  input_dialog
  test eax, eax
  jz   exit
  mov  esi, eax
  call ASCIIToNum
  mov  [num2], eax
  CDQ                  ;Sign-extend EAX into EDX:EAX
  IDIV  [num1]         ;Signed division of EDX:EAX by [num1]

  lea  esi, [mes+50]
  test eax, eax
  pushf
  jns  .Convert        ;Quotient was positive, no NEG needed
  neg  eax
.Convert:
  call NumToASCII
  popf
  jns  .Cout           ;Quotient was positive, no '-' needed
  dec  esi
  mov  byte [esi], '-'
.Cout:
  invoke  MessageBox, HWND_DESKTOP, esi, "Div is:", MB_OK
exit:
  invoke  ExitProcess,0
.end start

.input_resources

; Input: ESI
; Output: EAX
proc ASCIIToNum 
  push  ebx esi
  xor   eax, eax
  movzx ebx, byte [esi]
  cmp   bl, '-'
  pushf
  sete  bl             ;Number is positive, no unary '-' to skip
  add   esi, ebx
.next: 
  mov   bl, [esi]
  inc   esi
  test  bl, bl 
  jz    .done 
  sub   bl, 30h 
  imul  eax, 10
  add   eax, ebx 
  jmp   .next 
.done:
  popf
  jne   .pos           ;Number is positive, no NEG needed
  neg   eax
.pos:
  pop   esi ebx
  ret
endp 

; Input: EAX
; Output: ESI, EAX=0
proc NumToASCII
  push edx
  mov  byte [esi], 0 
.divloop:
  mov  dl, '0'
  shr  eax, 1
  adc  dl, 0
  dec  esi
  mov  [esi], dl
  test eax, eax
  jnz  .divloop
  pop  edx
  ret
endp