Який варіант краще використовувати для ділення цілого числа на 2?


406

Який із наведених методів є найкращим варіантом ділення цілого числа на 2 і чому?

Техніка 1:

x = x >> 1;

Техніка 2:

x = x / 2;

Ось xціле число.


75
Якщо ви дійсно хочете знову присвоїти результат x, жоден спосіб не підходить таким чином: він повинен бути або, x >>= 1або x /= 2залежно від того, що ви маєте намір висловити під час операції. Не тому, що це швидше (будь-який сучасний компілятор збирає всі еквівалентні варіанти в однакові, швидкі збірки все одно), а тому, що він менш заплутаний.
листопада 1212

33
Я не погоджуюся з рештою навколо. - Але я вважаю, що примітним є те, що в багатьох мовах програмування є операція, яка називається арифметичним зрушенням, яка утримує біт знаків на місці і для цього працює для підписаних значень, як очікувалося. Синтаксис може бути схожим x = x >>> 1. Також зауважте, що залежно від платформи та компілятора може бути цілком розумним вручну оптимізувати поділи та множення за допомогою зрушень. - Мислення мікроконтролерів, наприклад, без прямої підтримки ALU для множення.
JimmyB

36
Я вважаю за краще, x /= 2тому що x >>= 1виглядає занадто багато, як монадічне пов'язування;)
fredoverflow

19
@leftaroundabout - Я просто вважаю , що набагато більш зручним для читання , щоб писати x = x / 2замість x /= 2. Суб'єктивне уподобання можливо :)
JimmyB

8
@HannoBinder: безумовно, суб'єктивна, зокрема багато звички. IMO, мовою, де всі арифметичні оператори мають ⬜=комбінації, їх слід використовувати, коли це можливо. Вона видаляє шум і робить акцент на тому , що xє модифікованою , в той час як загальний =оператор , а говорить про те , що він бере на себе абсолютно нового значення , що не залежить від старого. - Завжди уникати комбінованих операторів (так що це читається так , хто знає тільки математичні оператор) може мати свою точку , а також, але тоді ви повинні були б відмовитися від вкрай корисних ++, --, +=теж.
близько

Відповіді:


847

Скористайтеся операцією, яка найкраще описує те, що ви намагаєтесь зробити.

  • Якщо ви розглядаєте число як послідовність бітів, використовуйте бітсифт.
  • Якщо ви трактуєте це як числове значення, використовуйте поділ.

Зауважте, що вони не зовсім рівноцінні. Вони можуть давати різні результати для від'ємних цілих чисел. Наприклад:

-5 / 2  = -2
-5 >> 1 = -3

(ideone)


20
Первісне питання також було невиразним щодо терміна "найкращий". "Найкраще" з точки зору швидкості, читабельності, екзаменаційного питання, щоб обдурити учнів тощо. За відсутності пояснень, що означає "найкраще", це здається найбільш правильною відповіддю.
Рей

47
У C ++ 03 обидва є реалізацією, визначеною для від'ємних чисел, і можуть дати однакові результати. У C ++ 11 поділ чітко визначено на від'ємні числа, але зміщення все ще визначено реалізацією.
Джеймс Канзе

2
У той час як визначення / є реалізацією (робить, якщо округлення вгору або вниз знижується за від'ємними числами), визначене на ранніх стандартах С. Він завжди повинен відповідати% (оператор модуля / залишку).
ctrl-alt-delor

7
"Визначено реалізацію" означає, що реалізатор компілятора має вибрати один з декількох варіантів реалізації, як правило, із суттєвими обмеженнями. Тут одне обмеження полягає в тому, що %і /оператори повинні відповідати як позитивним, так і негативним операндам, так що (a/b)*b+(a%b)==aце правда незалежно від ознак aі b. Зазвичай автор робить вибір, який дозволить отримати найкращі показники роботи з процесора.
RBerteig

6
Тож кожен, хто каже, що "компілятор перетворить його на зміну", помиляється, правда? Якщо компілятор не може гарантувати, що ви маєте справу з невід'ємним цілим числом (або це константа, або це непідписаний int), він не може змінити його на зміну
Kip

225

Чи схожий на перший поділ? Ні. Якщо ви хочете розділити, використовуйте x / 2. Компілятор може оптимізувати його, щоб по можливості використовувати біт-зсув (це називається зниження сили), що робить його марною мікрооптимізацією, якщо ви робите це самостійно.


15
Багато компіляторів не перетворять поділ потужністю двох у біт-зміну. Це було б неправильною оптимізацією для підписаних цілих чисел. Спробуйте поглянути на збірний висновок компілятора і переконатися в цьому.
exDM69

1
IIRC Я використовував це, щоб зробити паралельне скорочення швидше на CUDA (уникайте цілочисельних div). Однак це було більше року тому, мені цікаво, наскільки спритні компілятори CUDA в наш час.
Нілс

9
@ exDM69: Багато компіляторів будуть робити це навіть для підписаних цілих чисел, і просто налаштовують їх відповідно до підписаності.
Приємним

19
@ exDM69: І це актуально, як? Я сказав "якщо можливо", а не "завжди". Якщо оптимізація невірна, то, якщо це зробити вручну, це не зробить її правильною (плюс, як було сказано, GCC є досить розумним, щоб визначити належну заміну підписаних цілих чисел).
Cat Plus Plus

4
Переглядаючи сторінку WikiPedia, це, мабуть, суперечливо, але я б не назвав це зниженням сили. Зменшення міцності - це коли у циклі ви зменшуєте, наприклад, множення на додавання, додаючи до попередніх значень циклу. Це скоріше оптимізація видовищ, яку компілятори можуть зробити досить надійно.
SomeCallMeTim

189

Складати: є так багато причин на користь використання x = x / 2; Ось кілька:

  • це виражає ваші наміри чіткіше (якщо припустити, що ви не маєте справу з бітними подвійними реєстраційними бітами чи іншим)

  • компілятор все одно зменшить це до операції зсуву

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

  • якщо поділ буде частиною більшого виразу, ви, швидше за все, отримаєте право пріоритету, якщо будете використовувати оператор поділу:

    x = x / 2 + 5;
    x = x >> 1 + 5;  // not the same as above
  • підписана арифметика може ускладнити речі навіть більше, ніж проблема пріоритетності, згадана вище

  • ще раз повторюю - компілятор все одно зробить це для вас. Насправді це перетворить поділ на постійне на серію змін, додає та помножить на всілякі числа, а не лише на дві потужності. Дивіться це запитання для посилань на ще більше інформації про це.

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


5
Варто також додати, що хоча існують правила пріоритетності, у використанні круглих дужок немає нічого поганого. Під час оновлення деякого виробничого коду я фактично побачив щось із форми a/b/c*d(де a..dпозначалися числові змінні) замість набагато більш читабельного (a*d)/(b*c).

1
Продуктивність та оптимізація залежать від компілятора та цілі. Наприклад, я виконую деяку роботу з мікроконтролером, де щось вище, ніж -O0 вимкнено, якщо ви не купуєте комерційний компілятор, тож компілятор точно не перетвориться на бітчіфти. Крім того, бітчіффіксація займає один цикл, а ділення займає 18 циклів у цій цілі, а оскільки тактова частота мікроконтролерів досить низька, це може бути справді помітним враженням від продуктивності (але це залежить від вашого коду - ви обов'язково повинні використовувати / до того, як профайл вам скаже це проблема!)

4
@JackManey, якщо є ймовірність, що a*dабо b*cпризведе до переливу, менш читабельна форма не еквівалентна і має очевидну перевагу. PS Я згоден, що круглі дужки - ваш найкращий друг.
Марк Викуп 11

@MarkRansom - Справедливий момент (навіть якщо я зіткнувся a/b/c*dз кодом R - в контексті, коли переповнення означало б, що щось було серйозно не так з даними - а не в, скажімо, критичному для продуктивного блоку коді С).

Код x=x/2;є лише "чіткішим", ніж x>>=1якщо xніколи не буде непарне негативне число або його не хвилюють помилки, що входять в одну. Інакше x=x/2;і x>>=1;мають різні значення. Якщо то , що потрібно це значення обчислюється x>>=1, я вважав би , що , як ясніше , ніж x = (x & ~1)/2або x = (x < 0) ? (x-1)/2 : x/2, або будь-який інший композиції я можу думати , використовуючи поділ на два. Так само, якщо потрібне значення, обчислене через x/=2, це ясніше, ніж ((x + ((unsigned)x>>31)>>1).
supercat

62

Який із них найкращий варіант і чому для ділення цілого числа на 2?

Залежить від того, що ви маєте на увазі найкраще .

Якщо ви хочете, щоб ваші колеги ненавиділи вас або зробили ваш код важким для читання, я б неодмінно пішов із першим варіантом.

Якщо ви хочете поділити число на 2, перейдіть з другим.

Два не є рівнозначними, вони не поводяться однаково, якщо число від’ємне або всередині більших виразів - бітшіфт має нижчий пріоритет, ніж +або -, поділ має більший пріоритет.

Ви повинні написати свій код, щоб висловити його наміри. Якщо продуктивність викликає занепокоєння, не хвилюйтесь, оптимізатор добре працює в таких мікрооптимізаціях.


58

Просто використовуйте поділ ( /), припускаючи, що це зрозуміліше. Компілятор буде оптимізовано відповідно.


34
Компілятор повинен відповідно оптимізувати.
Noctis Skytower

12
Якщо компілятор не оптимізує відповідним чином, слід скористатися кращим компілятором.
Девід Стоун

3
@DavidStone: На яких процесорах компілятор може оптимізувати поділ можливо негативного підписаного цілого числа будь-якою постійною, окрім 1, та бути таким же ефективним, як зсув?
supercat

1
@supercat: Це хороший момент. Звичайно, ви можете зберегти значення в цілому цілі без підпису (який, на мою думку, має набагато гіршу репутацію, ніж слід, коли його поєднують із підписаними / неподписаними попередженнями про невідповідність), і більшість компіляторів також мають можливість сказати їм припустити, що щось є правдивим при оптимізації. . Я волів би обгортку , що в макросі сумісності і що - щось на зразок ASSUME(x >= 0); x /= 2;більш x >>= 1;, але це по - , як і раніше є важливим моментом , щоб підняти.
Девід Стоун

39

Я погоджуюся з іншими відповідями, які вам слід x / 2надати перевагу, оскільки його намір ясніший, і компілятор повинен оптимізувати його для вас.

Тим НЕ менше, ще одна причина віддати перевагу x / 2більш x >> 1, що поведінка >>залежить від реалізації , якщо xце знакова intі негативний.

З розділу 6.5.7, пункт 5 стандарту ISO C99:

Результат - E1 >> E2це E1зміщені E2бітові позиції вправо . Якщо E1має неподписаний тип або якщо E1має підписаний тип і негативне значення, значення результату є невід'ємною частиною коефіцієнта E1/ 2 E2. Якщо E1має підписаний тип та негативне значення, отримане значення визначається реалізацією.


3
Варто зазначити, що поведінка, яку визначають багато реалізацій x>>scalepowerна від'ємних числах, буде саме те, що потрібно при поділі значення на потужність двох для таких цілей, як відображення екрана, при цьому використання x/scalefactorбуде помилковим, якщо не застосовувати виправлення до негативних значень.
supercat

32

x / 2зрозуміліше і x >> 1не набагато швидше (згідно з мікро-орієнтиром, приблизно на 30% швидше для Java JVM). Як зазначали інші, округлення для від'ємних чисел дещо відрізняється, тому вам доведеться враховувати це, коли ви хочете обробити від’ємні числа. Деякі компілятори можуть автоматично конвертувати x / 2в , x >> 1якщо вони знають , що число не може бути негативним (навіть думав , що я не міг перевірити це).

Навіть x / 2не можна використовувати інструкцію процесора (повільного) поділу процесора, оскільки деякі ярлики можливі , але це все-таки повільніше, ніж x >> 1.

(Це питання C / C ++, інші мови програмування мають більше операторів. Для Java є також підписаний правий зсув x >>> 1, який знову відрізняється. Це дозволяє правильно обчислити середнє (середнє) значення двох значень, так що (a + b) >>> 1буде повернути середнє значення навіть для дуже великих значень aі b. Це потрібно, наприклад, для двійкового пошуку, якщо показники масиву можуть бути дуже великими. У багатьох версіях двійкового пошуку виникла помилка , оскільки вони використовувались (a + b) / 2для обчислення середнього значення. Це не означає не працюю правильно. Правильне рішення - (a + b) >>> 1замість цього використовувати .)


1
Компілятори не можуть перетворитись x/2на x>>1випадки, коли це xможе бути негативно. Якщо те, що хочеться, - це значення, яке x>>1було б обчислено, це майже напевно буде швидше, ніж будь-яке вираження, за допомогою x/2якого обчислюється однакове значення.
supercat

Ти правий. Компілятори можуть конвертувати лише x/2у тому x>>1випадку, якщо він знає, що значення не є негативним. Я спробую оновити свою відповідь.
Томас Мюллер

компілятори все-таки уникають divінструкції, перетворюючи x/2в (x + (x<0?1:0)) >> 1(де >> - це арифметичне зсув правої частини, який зміщується в знаки бітів). Для цього потрібно 4 інструкції: скопіюйте значення, shr (щоб отримати лише біт знака в регістрі), додати, sar. goo.gl/4F8Ms4
Пітер Кордес

Питання позначено як C і C ++.
Джош Санфорд

22

Кнут сказав:

Передчасна оптимізація - корінь усього зла.

Тому я пропоную використовувати x /= 2;

Таким чином код легко зрозуміти, а також я думаю, що оптимізація цієї операції в такому вигляді не означає великої різниці для процесора.


4
Що б ви вважали кращим методом зменшення числа на дві потужності, якщо потрібно, щоб цілі числа підтримували аксіому (що стосується натуральних чисел та дійсних чисел), що (n + d) / d = (n / d) + 1? Порушення, які аксіома при масштабуванні графіки, спричинить видимі «шви» в результаті. Якщо ви хочете чогось рівномірного і майже симетричного приблизно нуля, (n+8)>>4добре працює. Чи можете ви запропонувати будь-який підхід, який є настільки зрозумілим чи ефективним, не використовуючи підписаний правий зсув?
supercat

19

Погляньте на висновок компілятора, щоб допомогти вам прийняти рішення. Я провів цей тест на x86-64 з
gcc (GCC) 4.2.1 20070719 [FreeBSD]

Також дивіться результати компілятора в Інтернеті на godbolt .

Те, що ви бачите, компілятор використовує sarlв обох випадках інструкцію (арифметичне праворушення), тож вона визнає схожість між двома виразами. Якщо ви використовуєте ділення, компілятору також потрібно скоригуватися на від’ємні числа. Для цього він зміщує біт знака вниз до біта нижнього порядку і додає це до результату. Це виправляє проблему, що не відповідає одному, при зміщенні від'ємних чисел, порівняно з тим, що буде ділити.
Оскільки випадок поділу робить 2 зміни, а випадок явного зсуву - лише один, то тепер ми можемо пояснити деякі відмінності в продуктивності, виміряні іншими відповідями.

C код з складанням виводу:

Для розділення ваш внесок буде

int div2signed(int a) {
  return a / 2;
}

і це збирається в

    movl    %edi, %eax
    shrl    $31, %eax
    addl    %edi, %eax
    sarl    %eax
    ret

аналогічно для зміни

int shr2signed(int a) {
  return a >> 1;
}

з виходом:

    sarl    %edi
    movl    %edi, %eax
    ret

Залежно від того, що хтось робить, він може виправити помилку «за одним», або може призвести до помилки «за одним» (порівняно з тим, що потрібно), що потребує використання додаткового коду для її виправлення. Якщо те, що хочеться, - це результат, що рухається за межею, зміщення праворуч - швидше і простіше, ніж будь-яка інша мені відома альтернатива.
supercat

Якщо вам потрібна підлога, навряд чи ви опишете те, що ви хочете, як "ділення на 2"
Майкл Донохуе

Ділення як натуральних чисел, так і дійсних чисел підтримує аксіому, що (n + d) / d = (n / d) +1. Ділення дійсних чисел також підтримує (-n) / d = - (n / d), аксіома якої не має сенсу з натуральними числами. Неможливо мати оператора ділення, який закритий на цілі числа і підтримує обидві аксіоми. На мій погляд, сказати, що перша аксіома повинна містити всі числа, а друга лише для дійсних, здається більш природним, ніж сказати, що перша повинна містити для цілих чисел чи дійсних значень, але не для цілих чисел. Далі мені цікаво, у яких випадках друга аксіома насправді корисна .
supercat

1
Метод цілого поділу, який задовольняє першій аксіомі, розділить числовий рядок на області розміру d. Така секціонування корисна для багатьох цілей. Навіть якщо ви хочете мати точку розриву десь іншу, ніж між 0 і -1, додавання зміщення перемістить її. Ціле ділення, яке задовольняє другій аксіомі, розділить рядок чисел на регіони, які мають найбільший розмір d, але одна з них має розмір 2*d-1. Не зовсім "рівні" поділи. Чи можете ви запропонувати пропозиції про те, коли нечесний розділ насправді корисний?
supercat

Вихід компілятора для shr2signed неправильний. gcc на x86 вибирає реалізацію >> підписаних цілих чисел з арифметичними зрушеннями ( sar). goo.gl/KRgIkb . Це повідомлення в списку розсилки ( gcc.gnu.org/ml/gcc/2000-04/msg00152.html ) підтверджує, що gcc історично використовує арифметичні зрушення для підписаних входів, тому малоймовірно, що FreeBSD gcc 4.2.1 використовував непідписаний зсув. Я оновив вашу публікацію, щоб виправити це, і на початку абзацу сказано, що обидва використовуються shr, коли насправді SAR вони обидва використовують. SHR - це те, як він витягує біт знаків для /випадку. Також включено посилання на хрестовину.
Пітер Кордес

15

Просто додана примітка -

x * = 0,5 часто буде швидшим у деяких мовах, що базуються на VM - особливо сценаріїв дій, оскільки змінну не потрібно перевіряти на ділення на 0.


2
@minitech: Це такий поганий тест. Весь код у тесті є постійним. Перш ніж код навіть JITed, він усуне всі константи.

@ M28: Я був впевнений, що внутрішні дані jsPerf (тобто eval) роблять це щоразу знову. Незалежно, так, це досить поганий тест, тому що це дуже нерозумна оптимізація.
Ри-

13

Використовуйте x = x / 2; АБО x /= 2;Тому, що можливо, в майбутньому над ним працює новий програміст. Так йому буде простіше дізнатися, що відбувається в рядку коду. Кожна людина може не знати про такі оптимізації.


12

Я розповідаю з метою змагань з програмування. Як правило, вони мають дуже великі входи, де поділ на 2 відбувається багато разів, і відомо, що вхід позитивний чи негативний.

x >> 1 буде кращим, ніж x / 2. Я перевірив на ideone.com, запустивши програму, де відбулося більше 10 ^ 10 поділу на 2 операції. x / 2 зайняв майже 5,5 секунди, тоді як x >> 1 взяв майже 2,6 для тієї самої програми.


1
Для непідписаних значень компілятор повинен оптимізуватися x/2до x>>1. Для підписаних значень, майже всі реалізації визначають , x>>1щоб мати значення , яке еквівалентно , x/2але може бути обчислена швидше , коли xпозитивна, і це корисно відрізняється від x/2коли xнегативно.
supercat

12

Я б сказав, що слід розглянути кілька речей.

  1. Переміщення бітів повинно бути швидшим, оскільки для переміщення бітів справді не потрібні спеціальні обчислення, проте, як вказувалося, можливі проблеми з негативними числами. Якщо ви впевнені, що у вас є позитивні цифри, і ви шукаєте швидкості, то я б рекомендував битсифт.

  2. Оператор поділу для людей дуже легко читати. Тож якщо ви шукаєте читабельність коду, ви могли б скористатися цим. Зауважте, що поле оптимізації компілятора пройшло довгий шлях, тому полегшення практики читання та розуміння коду є хорошою практикою.

  3. Залежно від базового обладнання, операції можуть мати різну швидкість. Закон Амдала полягає в тому, щоб зробити загальну справу швидкою. Тож у вас може бути обладнання, яке може виконувати різні операції швидше, ніж інші. Наприклад, множення на 0,5 може бути швидшим, ніж ділення на 2. (Дозволено, вам може знадобитися взяти слово множення, якщо ви хочете застосувати ціле ділення).

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


2
"Бітшіфт повинен бути швидшим". компілятори оптимізують поділи на бітшіффіт
Тревор Хікі

Я сподіваюся, що вони будуть, але якщо у вас немає доступу до джерела компілятора, ви не можете бути впевнені :)
James Oravec

1
Я також рекомендую битшифф, якщо реалізація нею обробляється найпоширенішим способом, і спосіб, коли людина хоче обробляти негативні числа, відповідає тому, що >>робить, а не відповідає тому, що /робить.
supercat

12

Що стосується процесора, операції з переміщенням бітів проходять швидше, ніж операції поділу. Однак компілятор це знає і оптимізує належним чином настільки, наскільки це можливо, тож ви можете кодувати таким чином, щоб максимально зрозуміло та було легко, знаючи, що ваш код працює ефективно. Але пам’ятайте, що баночка unsigned int(в деяких випадках) може бути оптимізована краще, ніж з intпричин, зазначених раніше. Якщо вам не потрібен арифметичний підпис, не включайте біт знаків.


11

х = х / 2; є відповідним кодом для використання .. але операція залежить від вашої власної програми того, як саме ви хочете отримати результат.


11

Зробіть свої наміри яснішими ... наприклад, якщо ви хочете розділити, використовуйте x / 2, і дозвольте компілятору оптимізувати його для переміщення оператора (або будь-чого іншого).

Сьогоднішні процесори не дозволяють цим оптимізаціям вплинути на продуктивність ваших програм.


10

Відповідь на це залежатиме від середовища, в якому ви працюєте.

  • Якщо ви працюєте над 8-бітовим мікроконтролером чи іншим без апаратної підтримки для множення, зміна бітів очікується і звичайне явище, і поки компілятор майже напевно перетвориться x /= 2наx >>= 1 , наявність символу поділу призведе до більшої кількості брів у цьому середовищі, ніж використовуючи зсув для здійснення поділу.
  • Якщо ви працюєте в критичному для продуктивного середовища середовищі або в розділі коду, або ваш код може бути складений при відключенні оптимізації компілятора, x >>= 1 з коментарем, що пояснює його міркування, мабуть, найкраще саме для ясності мети.
  • Якщо ви не перебуваєте в одній з перерахованих вище умов, зробіть свій код читабельнішим просто використанням x /= 2. Краще збережіть наступного програміста, який випадково перегляне ваш код на 10-секундне подвійне виконання вашої операції зміни, ніж непотрібно доводити, що ви знали, що зміна була більш ефективною оптимізацією компілятора.

Всі ці припущення мають непідписані цілі числа. Простий зсув, мабуть, не те, що ви хочете для підписаних. Крім того, DanielH пропонує хороший момент щодо використання x *= 0.5для таких мов, як ActionScript.


8

мод 2, тест на = 1. не синтаксис у c. але це може бути найшвидшим.


7

як правило, правильний зсув ділиться:

q = i >> n; is the same as: q = i / 2**n;

це іноді використовується для прискорення програм ціною ясності. Я не думаю, що ти повинен це робити. Компілятор досить розумний для автоматичного виконання прискорення. Це означає, що введення змін у день не приносить вам нічого за рахунок ясності .

Погляньте на цю сторінку з Практичного програмування на C ++.


Якщо потрібно обчислити значення, яке, наприклад, (x+128)>>8було б обчислено для значень, що xне наближаються до максимуму, як це можна було б стисло зробити це без змін? Зверніть увагу, що (x+128)/256це не буде працювати. Чи знаєте ви якийсь приємний вираз, який буде?
supercat

7

Очевидно, якщо ви пишете свій код для наступного хлопця, який його читає, перейдіть до ясності "x / 2".

Однак якщо швидкість - ваша мета, спробуйте її як способами, так і часом. Кілька місяців тому я працював над програмою згортання растрових карт, яка передбачала перехід масиву цілих чисел і розділення кожного елемента на 2. Я робив усілякі речі для його оптимізації, включаючи старий трюк заміни "x >> 1" на "x / 2 ".

Коли я насправді приуротив обидва способи, я здивував, що x / 2 швидше, ніж x >> 1

Для цього використовується Microsoft VS2008 C ++ із увімкненими оптимізаціями за замовчуванням.


4

З точки зору продуктивності. Операції з перемикання процесора значно швидші, ніж діючі оп-коди. Таким чином, ділення на два або множення на 2 і т.д. всі виграють від операцій зсуву.

Щодо зовнішнього вигляду. Як інженери, коли ми стали настільки прихильні до косметики, що навіть прекрасні дами не користуються! :)


3

X / Y є правильним ... і ">>" оператором зсуву. Якщо ми хочемо два розділити ціле число, ми можемо використовувати (/) оператор дивідендів. Оператор shift використовується для переміщення бітів.

х = х / 2; х / = 2; ми можемо використовувати так ..


0

Хоча x >> 1 швидше, ніж x / 2, правильне використання >> при роботі з негативними значеннями трохи складніше. Для цього потрібно щось подібне до наступного:

// Extension Method
public static class Global {
    public static int ShiftDivBy2(this int x) {
        return (x < 0 ? x + 1 : x) >> 1;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.