Как правильно написать программу, которая вычисляет формулу?
Я пытался сделать программу, которая будет вычислять значение этой формулы:
(4b + c - d) (2b + 5(3c + 5a)) / (4ab + 5c - 8d)
Я попробовал написать хоть что-то, но совершенно ничего не происходит. Код — полный бред, который даже не компилируется.
Вопрос. Как написать правильный код? Не знаю, может это и тупой вопрос…
Data segment
Mess db 'Результат : ', '$'
a dw 0
b dw 0
c dw 0
d dw 0
Data ends
Code segment use16
assume cs: Code, ds: Data
Start:
mov ax, Data
mov ds, ax
PrtChr '>'
InputInt a
PrtChr '>'
InputInt b
PrtChr '>'
InputInt c
PrtChr '>'
InputInt d
Print Mess, 0
mov ax, b ; ax = b
mov cx, 4 ; cx = 4
imul cx; ; b * 4
add cx, c ; b * 4 + c
sub cx, d ; b * 4 + c - d
mov ax, 2 ; ax = 2
mov al, b ; al = b
imul al ; b * 2
mov ax, 5 ; ax = 5
mov cl, 3 ; cl = 3
mov ch, c ; ch = c
imul ch ; c * 3
mov ecx, 5 ; ecx = 5
mov eax, a ; eax = a
imul eax ; a * 5
add ch, eax ; ch = (3*c + 5*a)
imul ch ; 5 * (3 * c + 5 * a)
add al, ch ; (2 * b + (5 * ( 3 * c + 5 * a ) ) )
move ah, cx ; ah = b * 4 + c - d
move eax, al ; eax = (2 * b + (5 * ( 3 * c + 5 * a ) ) )
imul eax ; eax = (b * 4 + c - d) * (2 * b + (5 * ( 3 * c + 5 * a ) ) )
; 4 * a * b
move ax, 4 ; ax = 4
move ah, a ; ah = a
imul ah ; 4 * a
move ah, ah
move ax, b ; ax = b
imul ax ; 4 * a * b
; 5 * c
move ah, 5
move al, c
imul al
; 4 * a * b + 5 * c
add ah, al
; 8 * d
move al, 8 ; al = 8
move ecx, d ; ecx = d
imul ecx ; d * 8
; 4 * a * b + 5 * c - 8 * d
sub ah, ecx
KeyPressed
mov ax, 4C00h
int 21h
Code ends
Stk segment STACK
dw 128 dup(?)
Stk ends
Ответы (1 шт):
Расскажу вам небольшой секрет, который сохранит вам многие часы жизни:
Если вам дали задание написать что-то на ассемблере, то не надо писать это на ассемблере — напишите код на C, а потом скомпилируйте и посмотрите, какой ассемблерный код сгенерировал компилятор.
Например, в вашем случае, пишем нужную программу на C:
void
calc(void)
{
/* Значения могут быть любыми. */
int a = 2;
int b = 3;
int c = 5;
int d = 7;
int result = (4 * b + c - d) * (2 * b + 5 * (3 * c + 5 * a)) / (4 * a * b + 5 * c - 8 * d);
}
Затем компилируем её с выключенной оптимизацией (-O0) и с выдачей ассемблерного листинга (-S). Флаги -fno-asynchronous-unwind-tables и -fno-dwarf2-cfi-asm сделают ассемблерный листинг немного чище:
# p.c — название файла с исходным кодом
gcc -O0 -S -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm p.c
На выходе получаем вот такой вот ассемблерный листинг:
.file "p.c"
.text
.globl calc
.type calc, @function
calc:
pushq %rbp
movq %rsp, %rbp
movl $2, -20(%rbp)
movl $3, -16(%rbp)
movl $5, -12(%rbp)
movl $7, -8(%rbp)
movl -16(%rbp), %eax
leal 0(,%rax,4), %edx
movl -12(%rbp), %eax
addl %edx, %eax
subl -8(%rbp), %eax
movl %eax, %ecx
movl -16(%rbp), %eax
leal (%rax,%rax), %esi
movl -12(%rbp), %edx
movl %edx, %eax
addl %eax, %eax
leal (%rax,%rdx), %edi
movl -20(%rbp), %edx
movl %edx, %eax
sall $2, %eax
addl %edx, %eax
leal (%rdi,%rax), %edx
movl %edx, %eax
sall $2, %eax
addl %edx, %eax
addl %esi, %eax
imull %eax, %ecx
movl %ecx, %edx
movl -20(%rbp), %eax
imull -16(%rbp), %eax
leal 0(,%rax,4), %esi
movl -12(%rbp), %ecx
movl %ecx, %eax
sall $2, %eax
addl %ecx, %eax
leal (%rsi,%rax), %ecx
movl -8(%rbp), %eax
sall $3, %eax
subl %eax, %ecx
movl %edx, %eax
cltd
idivl %ecx
movl %eax, -4(%rbp)
nop
popq %rbp
ret
.size calc, .-calc
.ident "GCC: (GNU) 10.2.0"
.section .note.GNU-stack,"",@progbits
Иногда бывает удобнее использовать такой инструмент как Compiler Explorer.
Если вы занимаетесь для себя и хотите научится писать на ассемблере — все то же самое. Попытайтесь написать программу сами, если не получается, напишите тот же самый код на C и посмотрите, во что компилятор его перевел, какие конструкции ассемблера он использовал.
Пробуйте переводить C в ассемблер в ручную: берете распечатку кода на C и на соседнем листочке пишете ассемблерный код (можно и без распечатки, конечно). Не обязательно переводить большие программы, можете начать с небольших кусочков кода типа
int a = 4; // movl $4, -4(%rbp)
int b = 7; // movl $7, -8(%rbp)
// movl -4(%rbp), %edx
// movl -8(%rbp), %eax
// addl %edx, %eax
int c = a + b; // movl %eax, -12(%rbp)
int a = 5; // movl $5, -4(%rbp)
// jmp .L2
// .L3:
while (a > 0) { // movl $0, %eax
foo(); // call foo
a--; // subl $1, -4(%rbp)
} // .L2:
// cmpl $0, -4(%rbp)
// jg .L3