Другие языки программирования и технологии

При делении отрицательного числа выводит не правильный ответ (assembler). Если беру числа 127 13 10, пишет переполнение

; (a+b)/c-2

_stack segment STACK

dw 256 dup(0)

_stack ends

_data segment

msgA db 10, 13, "Input number A (-128..127): $"

msgB db 10, 13, "Input number B (-128..127): $"

msgC db 10, 13, "Input number C (-128..127): $"

msgError db 10, 13, "Error: wrong number. ", 10, 13, 24h

msgOver db 10, 13, "Error: overflow. ", 10, 13, 24h

buf db 5, 5 dup (0)

a db 0

b db 0

c db 0

x db ?

result db 10, 13, "Result: "

res db " $"

deg db 10

_data ends

_code segment

assume ss: _stack, ds: _data, cs: _code

out_shortint proc

push bx

mov bx, dx

cmp al, 0

je mm3; переходим если число равно нулю

jg mm1; переходим если число больше нуля

mov byte ptr [bx], 2dh; записываем минус в строку вывода

neg ax; инвертируем число

inc bx; изменяем адрес записи

mm1:cmp al, 100; сравниваем число с сотней

jl mm2; переходим если меньше

xor ah, ah

div deg; делим на 10

add ah, 30h; преобразуем в код

mov [bx+2], ah; записываем в строку вывода



mm2:xor ah, ah

div deg; делим на 10

;xchg ah, al

add ax, 3030h; преобразуем в код

cmp al, 30h; опускаем ведущий нуль

jne mm4; переход если нет вудущего нуля

mov al, 20h; записываем пробел вместо нуля



mm4:

mov word ptr [bx], ax; пишем в строку вывода

jmp ex; переходим к выходу

mm3:

mov word ptr [bx], 2030h; записываем нуль в строку вывода

ex:pop bx

ret

out_shortint endp

input_shortint proc

push bx

push cx

push si

mov ax, 0A00h

;lea dx, buf

int 21h

mov bx, dx

mov cl, [bx+1]

mov si, 2

xor ax, ax

mov dl, buf[si]

cmp dl, 2Dh

jne m1; переходим если неравны

inc si; пропускаем первый символ

;mov ax, word ptr buf[si]

dec cl; уменьшаем счетчик

m1:

mov dl, buf[si]; загружаем очередной символ

cmp dl, 30h; сравниваем с кодом '0'

jl m_error; переходим если меньше

cmp dl, 39h; сравниваем с "9"

jg m_error; переходим если больше

xor dl, 30h; преобразуем в цифру

add al, dl; складываем с предыдущим результатом

cmp ax, 127; сравниваем с максимальным числом

ja m_error; переходим если больше

cmp cx, 1; проверяем счетчик на окончание цикла

je m_con; переходим к концу цикла

mul deg; умножаем результат на 10, если не конец цикла

m_con:inc si; инкрементируем индекс

loop m1; повторяем если остались не рассмотренные символы

mov dl, buf[2]; проверяем строку на отрицательное число

cmp dl, 2Dh

jne quit; выходим если введено положительное число

neg al; инвертируем результат

jmp quit; выход



m_error:

lea dx, msgError; загружаем сообщение об ошибке

mov ax, 900h; функция вывода строки

int 21h; вызов дос

mov ah, 1; признак ошибки ввода

quit:

pop si; восстанавливаем регистры

pop cx

pop bx

ret

input_shortint endp

main proc; главная процедура

mov ax, _data; инициализация сегментного регистра данных

mov ds, ax

mov ax, 900h; вывод приглашения для ввода

lea dx, msgA

int 21h

lea dx, buf; адрес буфера

call input_shortint; вызов процедуры ввода числа

cmp ah, 1; была ли ошибка при вводе

je exit_error; выход при ошибке

mov a, al; помещаем число в сегмент данных



lea dx, msgB; вывод второго приглашения

mov ax, 900h

int 21h

lea dx, buf

call input_shortint

cmp ah, 1

je exit_error

mov b, al; помещаем второе число в сегмент данных



lea dx, msgC; вывод третьего приглашения

mov ax, 900h

int 21h

lea dx, buf

call input_shortint

cmp ah, 1

je exit_error

mov c, al; помещаем третье число в сегмент данных



mov al, a; помещаем a в аккумулятор

add al, b; прибавляем b

mov x, al

jo outOver; проверяем переполнение



cwd

div c; делим на c



jo outOver; проверяем переполнение

sub al, 2; вычитаем 2

jo outOver; проверяем переполнение

jmp outN; переходим к выводу результата

outOver:

lea dx, msgOver; загружаем сообщение об ошибке

mov ax, 900h

int 21h

jmp exit_error

outN:

lea dx, res

call out_shortint

mov ax, 900h

lea dx, result

int 21h

exit_error:

mov ax, 4C00h

int 21h

ret

main endp

_code ends

end main
Erkanat Seitnasim
Erkanat Seitnasim
321
Для деления отрицательных чисел действительно нужно применять команду idiv.
А при вводе 127, 13, 10 переполнение у вас возникает уже при сложении, т. к. 127 + 13 > 127.
Чтобы избежать переполнения, нужно расширять операнды до двух байт, а при делении придётся расширять делимое до четырёх.
На переполнение в этом случае проверяйте только конечный результат вычисления.

Подправленная программа:

; (a+b)/c-2
_stack segment STACK
  dw 256 dup (?)
_stack ends

_data segment
  msgA db 10, 13, "Input number A (-128..127): $"
  msgB db 10, 13, "Input number B (-128..127): $"
  msgC db 10, 13, "Input number C (-128..127): $"
  msgError db 10, 13, "Error: wrong number. ", 10, 13, 24h
  msgOver db 10, 13, "Error: overflow. ", 10, 13, 24h

  buf db 5, 5 dup (?)
  a db ?
  b db ?
  c db ?
  x db ?

  result db 10, 13, "Result: "
  res db 5 dup ("$")
  deg db 10
_data ends

_code segment
    assume ss: _stack, ds: _data, cs: _code

out_shortint proc
    push bx
    mov bx, dx
    cmp al, 0
    je mm3
    jg mm1
    mov byte ptr [bx], 2dh
    neg ax
    inc bx
mm1:
    cmp al, 100
    jl mm2
    xor ah, ah
    div deg
    add ah, 30h
    mov [bx+2], ah
mm2:
    xor ah, ah
    div deg
    add ax, 3030h
    cmp al, 30h
    jne mm4
    mov al, 20h
mm4:
    mov word ptr [bx], ax
    jmp ex
mm3:
    mov word ptr [bx], 2030h
ex:
    pop bx
    ret
out_shortint endp

input_shortint proc
    push bx
    push cx
    push si
    mov ah, 0Ah
    int 21h
    mov bx, dx
    mov cl, [bx+1]
    mov si, 2
    xor ax, ax
    mov dl, buf[si]
    cmp dl, 2Dh
    jne m1
    inc si
    dec cl
m1:
    mov dl, buf[si]
    cmp dl, 30h
    jl m_error
    cmp dl, 39h
    jg m_error
    xor dl, 30h
    add al, dl
    cmp ax, 127
    ja m_error
    cmp cx, 1
    je m_con
    mul deg
m_con:
    inc si
    loop m1
    mov dl, buf[2]
    cmp dl, 2Dh
    jne quit
    neg al
    jmp quit
m_error:
    lea dx, msgError
    mov ah, 9
    int 21h
    mov ah, 1
quit:
    pop si
    pop cx
    pop bx
    ret
input_shortint endp

main proc
    mov ax, _data
    mov ds, ax
    mov ah, 9
    lea dx, msgA
    int 21h
    lea dx, buf
    call input_shortint
    cmp ah, 1
    je exit_error
    mov a, al
    lea dx, msgB
    mov ah, 9
    int 21h
    lea dx, buf
    call input_shortint
    cmp ah, 1
    je exit_error
    mov b, al
    lea dx, msgC
    mov ah, 9
    int 21h
    lea dx, buf
    call input_shortint
    cmp ah, 1
    je exit_error
    mov c, al

    mov al, b
    cbw
    mov bx, ax
    mov al, c
    cbw
    mov cx, ax
    mov al, a
    cbw
    add ax, bx
    cwd
    idiv cx
    sub ax, 2
    mov x, al
    cwd
    xor ax, dx
    sub ax, dx
    cmp ax, 127
    ja outOver
    mov al, x
    jmp outN

outOver:
    lea dx, msgOver
    mov ah, 9
    int 21h
    jmp exit_error

outN:
    lea dx, res
    call out_shortint
    mov ah, 9
    lea dx, result
    int 21h
   
exit_error:
    mov ax, 0C07h
    int 21h
    mov ax, 4C00h
    int 21h
    ret
main endp

_code ends

    end main

Русик .
Русик .
51 590
Лучший ответ
Если у тебя деление со знаком - используй idiv.
Больше ничем помочь не могу, потому как смысел этой простыни от меня ускользает.
"неправильный"