Існуючі відповіді насправді не стосуються апаратної сторони речей, тому ось дещо під цим кутом зору. Загальноприйнята мудрість полягає в тому, що множення і ділення набагато повільніше, ніж зміщення, але реальна історія сьогодні є більш нюансованою.
Наприклад, безумовно, правда, що множення - це більш складна операція, яку потрібно реалізувати в апараті, але це не завжди завжди закінчується повільніше . Як виявляється, add
також значно складніше здійснити, ніж xor
(або взагалі будь-яку побітну операцію), але add
(і sub
) зазвичай отримують достатню кількість транзисторів, присвячених їх роботі, які в кінцевому підсумку є такими ж швидкими, як і бітові оператори. Таким чином, ви не можете просто розглядати складність впровадження обладнання як провідник швидкості.
Тож давайте детально розглянемо зміщення та "повне" операторів, таких як множення та зсув.
Зсув
Практично на всіх обладнаннях зрушення на постійну кількість (тобто кількість, яку компілятор може визначити за час компіляції) відбувається швидко . Зокрема, це зазвичай трапляється із затримкою одного циклу та з пропускною здатністю 1 на цикл чи вище. У деяких апаратних засобах (наприклад, на деяких мікросхемах Intel та ARM) певні зрушення на постійній основі можуть бути навіть "вільними", оскільки вони можуть бути вбудовані в іншу інструкцію ( lea
в Intel - особливі здібності перемикання першого джерела в ARM).
Зсув на змінну кількість - це більше сіра область. На старих пристроях це часом було дуже повільно, і швидкість змінювалася з покоління в покоління. Наприклад, при первинному випуску P4 від Intel, перехід на змінну кількість був, як відомо, повільним - вимагаючи часу, пропорційного розміру зрушення! На цій платформі використання множень для заміни змін може бути вигідним (тобто світ пішов вниз головою). Як на попередніх мікросхемах Intel, так і на наступних поколіннях, переміщення на змінну кількість не було настільки болючим.
На поточних мікросхемах Intel перехід на змінну кількість не особливо швидкий, але це теж не страшно. Архітектура x86 є зруйнованою, коли мова йде про змінні зсуви, оскільки вони визначали операцію незвичним способом: величини зміщення 0 не змінюють прапори стану, але всі інші зміни. Це гальмує ефективне перейменування регістра прапорів, оскільки його неможливо визначити, поки зсув не виконає, чи слід наступні інструкції читати коди умов, написані зсувом, або якусь попередню інструкцію. Крім того, зсуви записують лише до частини реєстру прапорів, що може спричинити часткову зупинку прапорів.
Підсумком цього є те, що в останніх архітектурах Intel зміна на змінну суму займає три "мікрооперації", тоді як більшість інших простих операцій (додавання, розрядних операцій, навіть множення) займають лише 1. Такі зрушення можуть виконуватися щонайбільше раз на 2 цикли .
Множення
Тенденція сучасного обладнання для настільних та ноутбуків - зробити множення швидкою роботою. На останніх мікросхемах Intel та AMD насправді може бути видано одне множення кожного циклу (ми називаємо цю зворотну пропускну здатність ). Однак затримка множення становить 3 цикли. Отже, це означає, що ви отримуєте результат будь-якого 3 циклу множення після його запуску, але ви можете починати нове множення кожного циклу. Яке значення (1 цикл або 3 цикли) є більш важливим, залежить від структури вашого алгоритму. Якщо множення є частиною ланцюга критичної залежності, важлива затримка. Якщо ні, то зворотна пропускна здатність чи інші фактори можуть бути важливішими.
Їх ключовим способом є те, що на сучасних мікросхемах ноутбуків (або краще) множення - це швидка операція, і, швидше за все, буде швидше, ніж 3 або 4 послідовності інструкцій, які компілятор видав би, щоб "отримати округлення" правильно для зменшення сили. Для змінних зрушень в Intel, як правило, кращим буде перемноження через вищезазначені проблеми.
На менших платформах форм-фактора множення може все-таки повільніше, оскільки для побудови повного і швидкого 32-розрядного або, особливо 64-розрядного множника потрібно багато транзисторів і потужності. Якщо хтось може заповнити деталі про ефективність множення на останніх мобільних мікросхемах, це буде дуже вдячно.
Розділити
Ділення - це і більш складна операція, що вимагає апаратного забезпечення, ніж множення, а також набагато рідше зустрічається у фактичному коді - це означає, що на неї ймовірно виділяється менше ресурсів. Тенденція сучасних чіпів все ще спрямована на швидші дільники, але навіть сучасні чіп-версії займають 10-40 циклів, щоб зробити поділ, і вони лише частково конвеєрні. Загалом, 64-бітове ділення навіть повільніше, ніж ділення 32-бітових. На відміну від більшості інших операцій, поділ може тривати змінну кількість циклів залежно від аргументів.
Уникайте поділів і замінюйте зміни (або дозвольте компілятору це зробити, але, можливо, вам доведеться перевірити збірку), якщо можете!