x / 2 + 100 * (a + b) - 3 / (c + d) + e * e в сборке
напишите алгоритм для: x / 2 + 100 * (a + b) - 3 / (c + d) + e * e, зная, что: a, c - слово, b, d - байт, e - двойное слово, x - qword
mov eax, dword [x]
mov edx, dword [x + 4] ; edx:eax = x
mov ebx, 2
idiv ebx ; eax = edx:eax / ebx = x / 2
mov ebx, eax ; save the result in ebx so we can do the other operations
mov al, [b]
cbw ; ax = b
add ax, [a] ; ax = a + b
mov dx, 100
imul dx ; dx:ax = ax * dx = 100 * (a + b)
push dx
push ax
pop eax ; 100 * (a + b)
add ebx, eax ; ebx = x / 2 + 100 * (a + b)
mov al, [d] ; al = d
cbw ; ax = d
add ax, word [c] ; ax = c + d
mov cx, ax ; cx = c + d
mov ax, 3
cwd
idiv cx ; ax = dx:ax / cx
cwd
push dx
push ax
pop eax ; eax = 3 / (c + d)
sub ebx, eax
mov eax, ebx
cdq ; edx:eax = x / 2 + 100 * (a + b) - 3 / (c + d)
mov ebx, eax
mov ecx, edx ; ecx:edx = x / 2 + 100 * (a + b) - 3 / (c + d)
mov eax, [e]
imul dword [e] ; edx:eax = e * e
add eax, ebx
adc edx, ecx
mov dword [result + 0], eax
mov dword [result + 4], edx
я сделал это излишне сложным?
Ответы
напишите алгоритм для: x / 2 + 100 * (a + b) - 3 / (c + d) + e * e
a, c - word,
b, d - byte,
e - doubleword,
x - qword
Поскольку ваше наибольшее число - 64 бита ( x - это qword), ваш окончательный результат тоже должен быть 64 бита!
Ваша первая операция заключалась в том, чтобы разделить qword в x на 2. Вы, кажется, ожидаете, что этот результат поместится только в одно двойное слово, потому что вы переместили частное в EBXрегистре. Вы не можете сделать это предположение и, что еще хуже, деление может легко привести к исключению деления, если частное не умещается в 32 бита.
Что касается решения, вы должны знать, что деление на 2 - это просто сдвиг вправо.
mov ebx, [x]
mov ebp, [x + 4] ; EBP:EBX is x
sar ebp, 1
rcr ebx, 1 ; EBP:EBX is x / 2
Это означает, что вам придется масштабировать и другие вычисления, чтобы добавить их к EBP:EBXusing:
add ebx, ...
adc ebp, ...
Поскольку сложение ассоциативно, вы можете начать с вычисления части e * e . Вы не переставляли выражение, и в итоге пришлось еще немного переставить регистры. Ничего страшного, но, по-моему, лучше:
mov eax, [e]
imul eax
add ebx, eax
adc ebp, edx
Затем идет 100 * (a + b) :
movsx eax, word [a]
movsx edx, byte [b]
add eax, edx ; eax = a + b
mov edx, 100
imul edx ; edx:eax = 100 * (a + b)
add ebx, eax
adc ebp, edx
Я оставлю тебе 3 / (c + d) ...
... и, наконец, конец будет:
sub ebx, eax
sbb ebp, edx
mov [result + 0], ebx
mov [result + 4], ebp
я сделал это излишне сложным?
Было немного сложно читать вашу программу, потому что вы не вставляли пустые строки между различными операциями.
Вам не нужно писать тег размера (байт, слово, двойное слово), если задействованный регистр уже подразумевает размер. В
mov dword [result + 0], eaxтеге dword есть избыточность.Лучше всего, чтобы комментарии в программе были выровнены друг над другом.
Перечитайте внимательно, чтобы избежать опечаток, например:
mov ecx, edx ; ecx:edx = x / 2 + 100 * (a + b) - 3 / (c + d)Должно быть
ECX:EBX.Чтобы вычислить квадрат: после того, как вы загрузили число в регистр, вы можете умножить его на тот же регистр и не обращаться к памяти во второй раз, как вы это делали:
mov eax, [e] imul eax ; Don't write "imul dword [e]"