Почему моя программа работает только с номерами pos или neg? - PullRequest
0 голосов
/ 15 ноября 2018

Мне нужно написать программу деления, которая принимает 2 десятичных числа (они могут быть положительными или отрицательными) и показывает ответ в двоичном коде.

Программа работает, но только с числами pos или neg.Когда я комментирую neg (под NeNegSum, я его пометил), он работает с числами neg и с 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 голосов
/ 21 марта 2019

Вы используете инструкцию DIV для вычисления num2 / num1. DIV используется для деления чисел без знака . Если вам нужно разделить числа со знаком (положительное и отрицательное), используйте инструкцию 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
...