Расчета (\$а^2\$ + \$б(2С-г)^2)/(3Е)\$ в сборе


Я сделал простую программу ассамблеи для оценки функции

$$Ф =\фрац{а^2 + б(2С-г)^2}{3Е}$$

Так как это по сути мой первый когда-либо, я хотел бы услышать, что можно улучшить И знаете, как лучше использовать регистры.

.model small
.stack 100h
.data 
a dw 4
b dw 15
c dw 86
d dw 155
e dw 8 
res dw 0;
.code
mov ax,@data
mov ds,ax
mov dx,0 
mov bx,0 
mov cx,0
mov ax,c
shl ax,1
mov bx,d
sub ax,bx
mul ax
mul b
mov dx,ax
push dx
mov dx,0
mov ax,a
mul ax
pop cx
add ax,cx
mov dx,ax
push dx
mov dx,0
mov ax,e
mov bx,3
mul bx
mov bx,ax
pop cx
mov ax,cx
mov cx,bx
div cx 
mov ax,4c00h
int 21h
end


227
13
задан 9 марта 2018 в 08:03 Источник Поделиться
Комментарии
2 ответа

Некоторые регистры имеют основную цель, и они должны быть использованы для тех, Но это не значит, что вы не можете использовать cx для хранения арифметические операции. Есть несколько вещей, которые вы могли бы улучшить ваш код

Комментарий

Я очень рекомендую вам начать собирать комментарии. Сборки не сложный язык, но это очень зависит от конкретных условий. Каждый подобный взгляд конвейера могут делать разные вещи в зависимости от контекста и комментарии очень важны, даже в таком небольшом коде приложения, как этот. Не пытайтесь писать то, что инструкция не на английском, как

add ax,cx ;adds content of cx to ax 

а объяснить смысл.

add ax,cx ;after that ax  = a^2 + b(2*c - d)^2

Сборка

Как я писал выше, нет ничего плохого в использовании сборки (если вы не используете какой-регистр, который может быть использован как сегмента), но есть несколько вещей, которые можно оптимизировать.

mov ax,0 

может быть написано как xor ax,ax и спас несколько байт (только если вы хотите). И вы не имеете к нулю ax & cx как вы не используете его, прежде чем назначать какое-либо значение для него.

Это странная конструкция:

mov dx,ax 
push dx
mov dx,0

Вы переезжаете в результате расчета dx пихать в стек и затем очистить реестр. Почему не просто

push ax

Инструкции, в конце и похоже, что они делают слишком много движущихся вокруг, так что это может быть упрощено как:

mov ax,e
mov bx,3
mul bx
mov bx,ax
pop ax
div bx

Вы пишете, что вы хотите использовать регистры более те push/pop также могут быть удалены. Также res это unsued в код - удалить его.

Итоговая программа (наверное - может быть еще более улучшено)

.model small
.stack 100h
.data
a dw 4
b dw 15
c dw 86
d dw 155
e dw 8
.code
_start:
mov ax,@data
mov ds,ax

xor dx,dx
mov ax,c
shl ax,1 ; ax = 2*c

mov bx,d
sub ax,bx ; ax = 2*c - d
mul ax ; ax = (2*c - d)^2
mul b ; ax = b*(2*c - d)^2
mov cx,ax

xor dx,dx
mov ax,e
mov bx,3
mul bx ; ax = 3*e
mov bx,ax

mov ax,a
mul ax ; ax = a^2
add ax,cx ; cx = a^2 + b*(2*c - d)^2

div bx ; ax = (a^2 + b*(2*c - d)^2)/3e

mov ax,4c00h
int 21h
end _start

5
ответ дан 10 марта 2018 в 05:03 Источник Поделиться

Сначала некоторые замечания по поводу вашего кода


mov dx,0 
mov bx,0
mov cx,0

Это практически никогда не нуждался в ноль регистров перед использованием. И если когда-нибудь это будет полезно протереть реестр чистить потом xor-Инг, зарегистрировать себе даст тот же результат, более эффективно. например xor bx, bx


mov bx,d
sub ax,bx

Есть смысл сначала двигать содержимое переменной Д в реестр и потом делать вычитание между регистрами, когда есть возможность вычесть переменную напрямую от аккумулятора письменной форме sub ax, d.


mov dx,ax
push dx
mov dx,0
mov ax,a
mul ax

Поскольку ваше намерение состоит в том, чтобы поместить значение в AX на стек, сделать это в один прием с push ax.
И очистка DX зарегистрируйтесь прямо перед mul инструкция расточительно с


  • DX среди материалов для умножения

  • DX получает высокие слова из 32-разрядного полученный продукт в любом случае

Вы можете применять несколько раз в вашей программе.


pop cx
mov ax,cx
mov cx,bx
div cx

Поскольку ваше намерение состоит в том, чтобы поместить значение в стек в AXделайте это в один присест с pop ax.
И двигать BX зарегистрироваться в CX зарегистрироваться, прежде чем div инструкция расточительна, так как разделение может просто работать на BX напрямую.

Далее некоторые улучшения можно применить


  • Вместо push-Инг / pop-Инг результат от Б(2С-г)^2, Вы можете перейти непосредственно к CX. Это очищает инструкция.

  • Вместо расчета стоимости с умножения, которая использует AX и, таким образом, требует от вас push / pop аккумулятор предварительно существующий контент, вы могли бы оценить с 3 Инструкции:

    mov bx, e   ; bx = 1e
    shl bx, 1 ; bx = 2e
    add bx, e ; bx = 3e

    Это сбривает 3 инструкция.


  • Перед операцией деления, вы должны нулю DX зарегистрироваться , но после последнего умножения до этого div инструкция листья DX=0он считает, что оптимизации не писать xor dx, dx здесь. Я прокомментировал в коде!

  • Наиболее важным усовершенствованием является то, что вы начали писать комментарии, которые поясняют, что инструкции в программе выполнить.

Применяя все вышеперечисленные

mov     ax, @data
mov ds, ax

mov ax, c ; ax = c
shl ax, 1 ; ax = 2c
sub ax, d ; ax = 2c - d
mul ax ; ax = (2c - d)^2
mul b ; ax = b(2c - d)^2
mov cx, ax ; cx = b(2c - d)^2

mov ax, a ; ax = a
mul ax ; ax = a^2

add ax, cx ; ax = a^2 + b(2c - d)^2

mov bx, e ; bx = e
shl bx, 1 ; bx = 2e
add bx, e ; bx = 3e

;;; xor dx, dx Previous MUL made DX=0
div bx ; ax = (a^2 + b(2c - d)^2) / 3e

mov ax, 4C00h ; DOS.TerminateWithExitcode
int 21h


Для повышения удобочитаемости ваших программ вы никогда не должны бояться использовать много пробелов.


Проверить imul

В программе, которую вы написали использует только 8086 инструкции. Возможно, это сделано намеренно.

Но если вы заинтересованы, x86 имеет очень мощный imul инструкция что


  • позволяет умножить немедленно

  • больше не ограничивается только аккумулятор.

Это, как выше код будет выглядеть так:

mov     ax, @data
mov ds, ax

imul cx, c, 2 ; cx = 2c
sub cx, d ; cx = 2c - d
imul cx, cx ; cx = (2c - d)^2
imul cx, b ; cx = b(2c - d)^2

mov ax, a ; ax = a
mul ax ; ax = a^2

add ax, cx ; ax = a^2 + b(2c - d)^2

imul bx, e, 3 ; bx = 3e

;;; xor dx, dx Previous MUL made DX=0
div bx ; ax = (a^2 + b(2c - d)^2) / 3e

mov ax, 4C00h ; DOS.TerminateWithExitcode
int 21h

Особенности расчета теперь очень просто!


Насчет переполнения?

Наконец, из-за точной проверки данных (а=4, Б=15, с=86, д=155, е=8), что ваша программа использует никаких рисков для перелива на эти расчеты.
В реалистичной программы же (например, тот, который использует числа пользователей вводить) вы всегда должны проверить на переполнение. Обратитесь к руководству, чтобы узнать о том, когда арифметические операции производить переполнение.

3
ответ дан 11 марта 2018 в 07:03 Источник Поделиться