is_реклам:

пошук, категорії та ін. показати ▼

Надшвидке множення і ділення

Надшвидке множення і ділення
автор опубліковано

Операції порозрядного зсуву мовою Асемблера переміщують окремі біти в байті (byte), слові (word) або подвійному слові (double word). Зсув може бути вліво або вправо. Відповідно, при зсуві вправо на одну позицію крайній правий (молодший) біт втрачається, а крайній лівий заміщується нулем. При зсуві на декілька позицій "виштовхується" вказана кількість бітів, а ті, що "звільнилися" заміщуються нулями.

Ротація (так званий циклічний зсув) не виштовхує біти, а повертає їх на місце тих, що "звільнилися". В результаті ротації вправо крайній правий біт стане на місце крайнього лівого, а решта бітів будуть зсунуті на одну позицію вправо.

Де це все можна застосувати, Ви зрозумієте із опису наступних команд.

Команди SHR і SHL та зсув беззнакових чисел

Команди SHR (SHift Right) і SHL (SHift Left) порозрядно зсувають беззнакові цілі числа вправо і вліво відповідно. Це найшвидший спосіб помножити або поділити ціле число на степінь двійки.

Уявімо число 5 в двійковій системі — 0101b. Після множення на 2 ми отримаємо 10, в двійковій системі це число 01010b. Порівнюючи два двійкових набори, Ви, напевно, вже помітили, як можна швидко отримати з числа 5 число 10, а саме за допомогою зсуву на один біт вліво, добавивши один нуль справа. Дедальніше процес зображений на ілюстрації нижче:

Так само можна помножити число на будь-який степінь двійки. Наприклад, замість множення на 16 (2 в 4 степені) можна зсунути вихідне число на 4 біти вліво.

Ділення на степінь двійки виконується за таким самим принципом, лише замість порозрядного зсуву вліво потрібно використовувати зсув вправо.

Команді SHL треба передавати два операнда:

SHL о1, о2

Перший повинен бути регістром або адресою пам'яті, його вміст треба зсунути. Другий операнд визначає число позицій, на які треба зсунути. Найчастіше це безпосереднє значення. Можна використовувати в якості другого операнда і регістр, але тільки не CL — це стосується всіх операцій зсуву і ротацій. Зсув можливий не більше ніж на 32 позиції, тому береться до уваги не весь другий операнд (якщо він великий), а остача від його ділення на 32.

Старший "виштовхнутий" біт зберігається в прапорці переносу CF (Carry Flag), а молодший біт замінюється нулем. Крім прапорця CF використовується прапорець знаку SF (Sighn Flag) і прапорець переповнення OF (Overflow Flag). За цими прапорцями необхідно слідкувати, виконуючи дії над числами зі знаком, щоб уникнути перетворення додатнього числа у від'ємне і навпаки (в цьому випадку прапорці SF і OF встановлюються в 1).

Команда SHR працює так само, як і SHL, тільки біти зсуваються вправо:

SHR o1, o2

Молодший біт переміщується в CF, а старший заміняється нулем.

А тепер розглянемо кілька прикладів, які допоможуть Вам краще засвоїти прочитане.

Приклад 1. Використовуючи SHR, поділимо вмістиме регістру AX на 16, не звертаючи уваги на переповнення:

SHR AX, 4 ; зсуваємо AX на 4 біти вправо (16=2^4)

Приклад 2. Підрахуємо кількість двійкових одиниць в AX і збережемо результат в BL.

АХ — це 16-розрядний регістр, тому ми повинні зсунути його вліво або вправо 16 разів. Після кожного зсуву ми аналізуємо прапорець переносу CF, в який потрапляє виштовхнутий біт, що дуже легко зробити за допомогою інструкції JC (JC — перехід на вказану мітку, якщо в CF знаходиться 1; JNC — перехід на вказану мітку, якщо в CF знаходиться 0). Якщо CF дорівнює одиниці, то збільшуємо лічильник BL.

MOV BL, 0 ; ініціалізуємо лічильник одиниць BL=0
MOV CX, 16 ; CX=16, стільки разів буде крутитися цикл
REPEAT: ; мітка початку циклу
SHR AX, 1 ; зсуваємо на 1 біт вправо, молодший біт попадає в CF
JNC NOT_ONE ; якщо CF=0, пропускаємо наступну команду, переходимо на мітку NOT_ONE
INC BL ; збільшуємо значення BL на 1 (операція інкременту)
NOT_ONE: ; мітка закінчення циклу
LOOP REPEAT ; зациклюємось на мітку REPEAT

Після виконання цього фрагменту коду регістр BL буде містити кількість одиниць регістра AX, а сам регістр AX буде містити нуль.

Команди SAL і SAR та
зсув чисел зі знаком

Команди SAL і SAR виконуються для порозрядного зсуву цілих чисел зі знаком (арифметичний зсув). Команда SAL — це зсув вліво, а команда SAR — вправо.

Формат команд такий:

SAL o1, o2
SAR o1, o2

Команда SAR зсуває всі біти, крім старшого, що позначає знак числа -- цей біт зберігається. Молодший біт, як звичайно, витісняється в CF. Операнди обох інструкцій такі ж, як і у SHL і SHR.

Команди RCR і RCL та ротація через прапорець переносу

Ці команди виконують циклічний порозрядний зсув (ротацію). RCR діє так само, як SHR, але замість нуля в старший біт першого операнда заноситься попереднє вмістиме CF. Вихідний молодший біт витісняється в CF. Команда RCL працює подібно до RCR, тільки в зворотному напрямку.

Формат команд такий:

RCR o1, o2
RCL o1, o2

Команди ROR і ROL та ротація з винесенням в прапорець переносу

Ці команди виконують інший варіант циклічного зсуву: ROR спочатку копіює молодший біт першого операнду в його старший біт, а потім заносить його в CF; ROL працює в оберненому напрямку.

ROR o1, o2
ROL o1, o2

Операнди цих команд аналогічні операндам команд RCR і RCL.

В наступних статтях підкатегорії Архітектура ми розповімо як за допомогою побітових зсувів визначити парність числа, переставити біти в зворотньому порядку та інші цікаві застосування цих простих і швидких команд.

Що почитати на цю тему? Рудольф Марек. Ассемблер на примерах. Базовый курс.

схоже за тегами

Залишити коментар:

Яндекс цитирования UA TOP Bloggers