Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 14.01.2023, 13:17   #1
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию Упростить и сократить код

[CODE]; TASM Вычислить Выражение (переменные вводятся с клавиатуры) a*c*(a+b)-d
; a, b, c – define byte, d – define word
.model small
.code
a db 0
b db 0
c db 0
d dw 0
res dw 0
start: mov ax,cs
mov ds,ax
mov es,ax
call pthis
db "'a*c*(a+b)-d' calculator",13,10,0
call pthis
db 13,10,"byte a=",0
call scan_byte
mov a,cl
call pthis
db 13,10,"byte b=",0
call scan_byte
mov b,cl
call pthis
db 13,10,"byte c=",0
call scan_byte
mov c,cl
call pthis
db 13,10,"word d=",0
call scan_num
mov d,cx
mov al,a
mov bl,b
mov ah,0
mov bh,0
add ax,bx
cmp ah,0
jnz over1
mov ah,c
mul ah ; ax=c*(a+b)
mov cx,ax
mov al,a
mov ah,0
mul cx ; ax=a*c*(a+b)
cmp dx,0
jnz over1
sub ax,d ; ax=a*c*(a+b)-d
mov res,ax
call pthis
db 13,10,"result=",0
mov ax,res
call print_num
int 20h ; выход в Дос
over1: call pthis
db "Number is out of bounds",0
int 20h ; выход в Дос
scan_byte:call scan_num ; ввести число
cmp ch,0 ; число не умещается в байт ?
jnz over1
ret ; иначе возврат
;****************************
; include io86.inc
; ***************************
; Подпрограммы ввода и вывода
; ***************************
; this macro prints a char in AL and advances
; the current cursor position:
; макро - вывод символа char на дисплей

PUTC MACRO char
PUSH AX
push dx
MOV DL, char
MOV AH, 2
INT 21h
pop dx
POP AX
ENDM

;
; CALL PTHIS
; db 'Hello World!', 0
;
PTHIS:

MOV CS:temp1, SI ; store SI register.

POP SI ; get return address (IP).

PUSH AX ; store AX register.

next_char:
MOV AL, CS:[SI]
INC SI ; next byte.
CMP AL, 0
JZ printed
MOV AH, 0Eh ; teletype function.
INT 10h
JMP next_char ; loop.
printed:

POP AX ; re-store AX register.

; SI should point to next command after
; the CALL instruction and string definition:
PUSH SI ; save new return address into the Stack.

MOV SI, CS:temp1 ; re-store SI register.

RET
temp1 DW ? ; variable to store original value of SI register.


; ввод числа CX со знаком
SCAN_NUM:
PUSH DX
PUSH AX
PUSH SI

MOV CX, 0 ; начальное значение cx=0

; reset flag:
MOV CS:make_minus, 0

next_digit: ; начало цикла ввода

; get char from keyboard
; into AL:
MOV AH, 00h ; ввести символ AL с клавиатуры...
INT 16h
; and print it:
MOV AH, 0Eh ; ... и напечатать его
INT 10h

; check for MINUS:
CMP AL, '-' ; проверить ввод знака минус
JE set_minus

; check for ENTER key:
CMP AL, 13 ; carriage return? ; если enter то выход из подпрограммы
JNE not_cr
JMP stop_input
not_cr:


CMP AL, 8 ; 'BACKSPACE' pressed? - забой - убрать последнюю цифру
JNE backspace_checked
MOV DX, 0 ; remove last digit by
MOV AX, CX ; division:
DIV CS:ten ; AX = DX:AX / 10 (DX-rem).
MOV CX, AX
PUTC ' ' ; clear position. ; стереть последнюю цифру с дисплея
PUTC 8 ; backspace again.
JMP next_digit
backspace_checked:


; allow only digits:
CMP AL, '0' ; это цифра ?
JAE ok_AE_0
JMP remove_not_digit
ok_AE_0:
CMP AL, '9'
JBE ok_digit
remove_not_digit:
PUTC 8 ; backspace. ; это не цифра - стереть символ
PUTC ' ' ; clear last entered not digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for next input.
ok_digit: ; да, это цифра


; multiply CX by 10 (first time the result is zero) ; умножить cx на 10
PUSH AX
MOV AX, CX
MUL CS:ten ; DX:AX = AX*10
MOV CX, AX
POP AX

; check if the number is too big
; (result should be 16 bits)
CMP DX, 0 ; если число не влезает в 16 бит, то переход на too_big
JNE too_big

; convert from ASCII code:
SUB AL, 30h ; преобразовать код символа в цифру

; add AL to CX: ; CX=CX+AX
MOV AH, 0
MOV DX, CX ; backup, in case the result will be too big.
ADD CX, AX
JC too_big2 ; jump if the number is too big.

JMP next_digit
alonil вне форума Ответить с цитированием
Старый 14.01.2023, 13:17   #2
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию

set_minus:
MOV CS:make_minus, 1
JMP next_digit

too_big2: ; отмена, если число слишком большое вариант 2
MOV CX, DX ; restore the backuped value before add.
MOV DX, 0 ; DX was zero before backup!
too_big: ; отмена, если число слишком большое
MOV AX, CX
DIV CS:ten ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
MOV CX, AX
PUTC 8 ; backspace. ; затереть последнюю цифру
PUTC ' ' ; clear last entered digit.
PUTC 8 ; backspace again.
JMP next_digit ; wait for Enter/Backspace. ; переход к началу цикла ввода


stop_input: ; если был введен минус, то изменить знак CX
; check flag:
CMP CS:make_minus, 0
JE not_minus
NEG CX
not_minus: ; всё сделано - выход из подпрограммы

POP SI
POP AX
POP DX
RET
make_minus DB ? ; used as a flag. флаг "был введён минус"

; печать числа AX со знаком
PRINT_NUM:
PUSH DX
PUSH AX

CMP AX, 0
JNZ not_zero

PUTC '0' ; если число=0 то просто напечатать "0" и выйти
JMP printed2

not_zero:
; the check SIGN of AX,
; make absolute if it's negative:
CMP AX, 0
JNS positive
NEG AX ; если число отрицательное, то напечатать минус и изменить знак числа

PUTC '-'

positive:
CALL PRINT_NUM_UNS ; вызвать подпрограмму "печать числа без знака"
printed2:
POP AX
POP DX
RET ; выход

; печать числа AX без знака
PRINT_NUM_UNS:

PUSH AX
PUSH BX
PUSH CX
PUSH DX

; flag to prevent printing zeros before number:
MOV CX, 1 ; флаг "не печатать нули перед числом"

; (result of "/ 10000" is always less or equal to 9).
MOV BX, 10000 ; 2710h - divider. ; делитель=10000

; AX is zero?
CMP AX, 0
JZ print_zero

begin_print:

; check divider (if zero go to end_print):
CMP BX,0 ; если bx=0 то закончить печать
JZ end_print

; avoid printing zeros before number:
CMP CX, 0 ; не печатать лидирующие нули
JE calc
; if AX<BX then result of DIV will be zero:
CMP AX, BX ; если AX<BX то результат деления=0
JB skip
calc:
MOV CX, 0 ; set flag.

MOV DX, 0
DIV BX ; AX = DX:AX / BX (DX=remainder).

; print last digit
; AH is always ZERO, so it's ignored
ADD AL, 30h ; convert to ASCII code.
PUTC AL ; напечатать очередную цифру


MOV AX, DX ; get remainder from last div. ; AX=остаток от последнего деления

skip:
; calculate вычислить BX=BX/10
PUSH AX
MOV DX, 0
MOV AX, BX
DIV CS:ten ; AX = DX:AX / 10 (DX=remainder).
MOV BX, AX
POP AX

JMP begin_print ; переход к началу цикла

print_zero:
PUTC '0' ; напечатать "0"

end_print: ; выход из подпрограммы

POP DX
POP CX
POP BX
POP AX
RET
ten DW 10 ; used as divider. ; константа делитель

end start[/CODE]
alonil вне форума Ответить с цитированием
Старый 14.01.2023, 13:21   #3
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию

Нужно упростить без подпрогарамм и макрокоманд и процедур.Я пытался корректировать и сокращать прогу,но у меня она по другому не работает.А нужно как-то это всё дело упроститьи сократить,как сказали мне как минимум в половину.Помогите,пожалуйста.
alonil вне форума Ответить с цитированием
Старый 14.01.2023, 14:09   #4
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Так используйте вместо процедуры посимвольного ввода цифр числа функцию чтения строки и ее анализ после ввода. Будет гораздо короче.

Код:
    mov ax, 0C07h ; Очистка буфера ввода клавиатуры
    int 33
    mov dx, offset buffer ; ввод строки в буфер
    mov ah, 10
    int 33
    xor cx, cx ; Начальное значение для ввода
    mov si, offset buffer ; Буфер для ввода
    lodsb ; Пропускаем байт длины буфера
    lodsb ; Считываем первый символ
    cmp al, '-' ; Если первый символ минус, тогда просто его пропускаем
    jnz chkdigit
    lodsb
chkdigit: ; Проверяем символы в буфере на диапазон '0' .. '9'
    lodsb
    cmp al, '0'
    jc notdigit
    cmp al, '9'
    ja notdigit
    sub al, '0' ; Преобразуем код символа в цифору
    xchg ax, cx
    mov dx, 10
    mul dx ; Умножаем введенное число на 10
    add cx, ax ; и прибавляем новую цифру
    adc dx, 0 ; Если после умножения или сложения был перенос, тогда выходим с ошибкой
    jnz chkdigit
invalidinput:
    xor ax, ax ; Выход с ошибкой (флаг cf = 1) и результатом = 0
    stc
    retn
notdigit:
    xchg ax, cx ; Переносим число в ax, а символ отличный от цифры в cl
    cmp cl, ' ' ; Если символ равен Space, тогда ввод завершен удачно
    jz inputok
    cmp cl, 9 ; Если символ равен Tab, тогда ввод завершен удачно
    jz inputok
    cmp cl, 13 ; Если символ не равен Enter, тогда 
    jnz invalidinput
inputok:
    cmp buffer[1], '-' ; Если первый символ в буфере равен минусу, тогда число должно быть отрицательным
    jnz positive
    neg ax
positive:
    clc ; Выход без ошибок
    retn
buffer db 8, 8 dup 0 ; минимально возможное число -32767 == 6 символов; максимальное - 32767 == 5 символов; еще в конце будет символы ввода 13, 10; итого максимальная длина буфера 8 символов.
И вот функция ввода чисел сразу стала намного короче.
macomics вне форума Ответить с цитированием
Старый 14.01.2023, 17:11   #5
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию

Код:
.model small
 stk segment stack
    db 256 dup(?)
stk ends
data segment
        _ENTER_         =       0Dh
        CrLf            db      0Dh, 0Ah, '$'
        msgPressAnyKey  db      0Dh, 0Ah, 'Press any key to exit...', '$'
 
        Prompt_A        db      0Dh, 0Ah, "Input A (define byte): ", '$'
        Prompt_B        db      0Dh, 0Ah, "Input B (define byte): ", '$'
        Prompt_C        db      0Dh, 0Ah, "Input C (define byte): ", '$'
        Prompt_D        db      0Dh, 0Ah, "Input D (define word): ", '$'
        msgResult       db      0Dh, 0Ah, "Result a*c*(a+b)-d: ", '$'
        a              db      ?
        b              db      ?
        c              db      ?
        d              dw      ?
        Result          dw      ?
data ends
code segment
    assume cs:code,ds:data,ss:stk
start:
        ;инициализация сегментного регистра ds адресом сегмента данных
        mov     ax,     data
        mov     ds,     ax
 
        ;ввод a
        mov     ah,     09h
        lea     dx,     [Prompt_A]
        int     21h
        xor     bx,     bx      ;признак положительного числа
        xor     cx,     cx      ;введённое число
        a_do:
                mov     ah,     00h
                int     16h
                mov     dl,     al
                cmp     al,     _ENTER_
                je      a_break
                cmp     al,     '-'
                jne     a_endif
                        mov     bx,     1
                        jmp     a_putchar
                a_endif:
                sub     al,     '0'
                jc      a_do
                cmp     al,     9+1
                jnc     a_do
                xor     ah,     ah
                shl     cx,     1       ;cx=cx*10
                mov     si,     cx
                shl     cx,     1
                shl     cx,     1
                add     cx,     si
                add     cx,     ax      ;cx=cx+ax
        a_putchar:
                mov     ah,     02h
                int     21h
        jmp     a_do
a_break:
        mov     ax,     cx
        test    bx,     bx
        jz      a_exit
        neg     ax
a_exit:
        mov     [a],   al
        ;ввод b
        mov     ah,     09h
        lea     dx,     [Prompt_B]
        int     21h
        xor     bx,     bx      ;признак положительного числа
        xor     cx,     cx      ;введённое число
        b_do:
                mov     ah,     00h
                int     16h
                mov     dl,     al
                cmp     al,     _ENTER_
                je      b_break
                cmp     al,     '-'
                jne     b_endif
                        mov     bx,     1
                        jmp     b_putchar
                b_endif:
                sub     al,     '0'
                jc      b_do
                cmp     al,     9+1
                jnc     b_do
                xor     ah,     ah
                shl     cx,     1       ;cx=cx*10
                mov     si,     cx
                shl     cx,     1
                shl     cx,     1
                add     cx,     si
                add     cx,     ax      ;cx=cx+ax
        b_putchar:
                mov     ah,     02h
                int     21h
        jmp     b_do
b_break:
        mov     ax,     cx
        test    bx,     bx
        jz      b_exit
        neg     ax
b_exit:
        mov     [b],   al
        ;ввод c
        mov     ah,     09h
        lea     dx,     [Prompt_C]
        int     21h
        xor     bx,     bx      ;признак положительного числа
        xor     cx,     cx      ;введённое число
        c_do:
                mov     ah,     00h
                int     16h
                mov     dl,     al
                cmp     al,     _ENTER_
                je      c_break
                cmp     al,     '-'
                jne     c_endif
                        mov     bx,     1
                        jmp     c_putchar
                c_endif:
                sub     al,     '0'
                jc      c_do
                cmp     al,     9+1
                jnc     c_do
                xor     ah,     ah
                shl     cx,     1       ;cx=cx*10
                mov     si,     cx
                shl     cx,     1
                shl     cx,     1
                add     cx,     si
                add     cx,     ax      ;cx=cx+ax
        c_putchar:
                mov     ah,     02h
                int     21h
        jmp     c_do
c_break:
        mov     ax,     cx
        test    bx,     bx
        jz      c_exit
        neg     ax
c_exit:
        mov     [c],   al
        ;ввод d
        mov     ah,     09h
        lea     dx,     [Prompt_D]
        int     21h
        xor     bx,     bx      ;признак положительного числа
        xor     cx,     cx      ;введённое число
        d_do:
                mov     ah,     00h
                int     16h
                mov     dl,     al
                cmp     al,     _ENTER_
                je      d_break
                cmp     al,     '-'
                jne     d_endif
                        mov     bx,     1
                        jmp     d_putchar
                d_endif:
                sub     al,     '0'
                jc      d_do
                cmp     al,     9+1
                jnc     d_do
                xor     ah,     ah
                shl     cx,     1       ;cx=cx*10
                mov     si,     cx
                shl     cx,     1
                shl     cx,     1
                add     cx,     si
                add     cx,     ax      ;cx=cx+ax
        d_putchar:
                mov     ah,     02h
                int     21h
        jmp     d_do
d_break:
        mov     ax,     cx
        test    bx,     bx
        jz      d_exit
        neg     ax
d_exit:
        mov     [_d],   ax
 
 
        mov     al,     [_a]
        imul    [_c]
        mov     bx,     ax
 
        mov     al,     [_a]
        add     al,     [_b]
        cbw
 
        imul    bx
 
        sub     ax,     [d]
 
        mov     [Result],       ax
 
        mov     ah,     09h
        lea     dx,     [msgResult]
        int     21h
        mov     ax,     [Result]
        mov     bx,     10      ;основание системы счисления (делитель)
        xor     cx,     cx      ;количество символов в модуле числа
        or      ax,     ax      ;для отрицательного числа
        jns     @@div
                neg     ax      ;поменять знак (сделать положительным)
                push    ax      ;и вывести на экран символ "-" (минус)
                mov     ah,     02h
                mov     dl,     '-'
                int     21h
                pop     ax
        @@div:                  ;делим число на 10
                xor     dx,     dx
                div     bx
                push    dx      ;остаток сохраняем в стеке
                inc     cx      ;количество цифр в числе
                or      ax,     ax
        jnz     @@div           ;повторяем, пока в числе есть цифры
        mov     ah,     02h
        @@store:
                pop     dx      ;извлекаем цифры (остатки от деления на 10) из стека
                add     dl,     '0'     ;преобразуем в символы цифр
                int     21h     ;и выводим их на экран
        loop    @@store
        ;ожидание нажатия любой клавиши
        mov     ah,     09h
        lea     dx,     [msgPressAnyKey]
        int     21h
 
        mov     ah,     00h
        int     16h
 
        ;завершение программы
        mov     ax,     4C00h
        int     21h

        end     start
alonil вне форума Ответить с цитированием
Старый 14.01.2023, 17:12   #6
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию

Спасибо.
я тут сделал еще один код попытался .Но там содержимое некоторых меток повторяется.Можно эти метки записать только один раз и после вывода каждого сообщения с просьбой ввести новую переменную переходить к этим метках а потом вводить уже значения переменных?Но сделать это без процедур и макрокоманд.Помогите,пожалуйста? c 'nbv
alonil вне форума Ответить с цитированием
Старый 14.01.2023, 19:46   #7
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Так расположите переменные перед или после соответствующего Prompt. Тогда позиция переменной будет известна для своего запроса. Достаточно будет сделать цикл с запросами этих переменных по их количеству
Код:
.data
Buffer db 8, 0, 0, 0, 0, 0, 0, 0, 0
; ? - вводимое значение переменной
; 0FF80h или 08000h - маска проверки диапазона (Если число не соответствует этой маске, тогда оно выйдет за границы byte или word)
; Третье значение это метка следующего запроса для ввода. -1 - конец цикла ввода
Value_A dw ?, 0FF80h, Value_B
Prompt_A db 0Dh, 0Ah, "Input A (define byte): ", '$'
Value_B dw ?, 0FF80h, Value_C
Prompt_B db 0Dh, 0Ah, "Input B (define byte): ", '$'
Value_C dw ?, 0FF80h, Value_D
Prompt_C db 0Dh, 0Ah, "Input C (define byte): ", '$'
Value_D dw ?, 08000h, -1
Prompt_D db 0Dh, 0Ah, "Input D (define word): ", '$'

.code
startup:
    mov ax, @data
    mov ds, ax

    lea dx, Value_A
input_loop:
    push dx
    mov ah, 9
    add dx, 6
    int 33
    mov ax, 3079
    int 33
    lea dx, Buffer
    mov ah, 10
    int 33
    xor cx, cx
    lea si, Buffer
    lodsb
    lodsb
    cmp al, '-'
    jnz is_digit
    lodsb
is_digit:
    cmp al, '0'
    jc not_digit
    cmp al, '9'
    ja not_digit
    sub al, '0'
    xchg ax, cx
    mov dx, 10
    mul dx
    add cx, ax
    adc dx, 0
    jz is_digit
    jmp overflow
not_digit:
    xchg ax, cx
    cmp al, ' '
    jz number
    cmp al, 9
    jz number
    cmp al, 13
    jnz not_number
number:
    pop bx
    test cx, word ptr [bx + 2]
    jnz overflow
    cmp byte ptr Buffer[1], '-'
    jnz positive
    neg cx
positive:
    mov dx, word ptr [bx + 4] ; Переход к вводу следующего числа
    mov word ptr [bx], cx
    cmp dx, -1
    jnz input_loop
; Введены значения переменных a, b, c и d. Можете посчитать значение выражения с ними
...
; Вывод результата и выход
...
   xor al, al
   int 32

overflow:
; Введенное число вне диапазона
    lea dx, Error_not_Number
    jmp print_error

not_number:
; Введено не число (встретились символы не цифры)
    lea dx, Error_not_Number
print_error:
    mov ah, 9
    pop bx ; Сбалансировать стек
    int 33
    or al, -1
    int 32

Последний раз редактировалось macomics; 14.01.2023 в 19:55.
macomics вне форума Ответить с цитированием
Старый 14.01.2023, 20:48   #8
alonil
Пользователь
 
Регистрация: 14.01.2023
Сообщений: 38
По умолчанию

Спасибо!
alonil вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
как сократить код? Александр121 Общие вопросы C/C++ 3 02.08.2018 08:50
сократить код Kirja23 Microsoft Office Excel 1 20.02.2013 22:34
Как сократить код Вадим12091965 Microsoft Office Excel 6 28.10.2012 11:04
Нужно упростить (не сократить) задачу. PascalAbc. AntoshkaK Паскаль, Turbo Pascal, PascalABC.NET 13 04.12.2011 02:26
Как сократить код DLL ProgDel Общие вопросы Delphi 3 16.02.2010 21:12