dyst0p

На сколько же битовые сдвиги быстрее умножения/деления надвое

Повторяю сейчас поразрядные операции применительно к СSharp и решил проверить давно интересовавший меня вопрос.

Я встречал 2 противоположных мнения:

Собственно, почему бы и не проверить? Т.к. меня интересует вся эта тема применительно к разработке в Unity, я создал пустую сцену с пустым объектом, к которому подвязал скрипт:

// сорян за говнокод using UnityEngine; using System; public class Test : MonoBehaviour { int msBeforeCount; int msDelta; int numberOfIteration = 1000000000; void Start() { int i = 0; msBeforeCount = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; for (int j = 0; j < numberOfIteration; j++) { i *= 2; } msDelta = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond - msBeforeCount; Debug.Log($"i *= 2 took {msDelta}ms"); msBeforeCount = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; for (int j = 0; j < numberOfIteration; j++) { i /= 2; } msDelta = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond - msBeforeCount; Debug.Log($"i /= 2 took {msDelta}ms"); msBeforeCount = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; for (int j = 0; j < numberOfIteration; j++) { i = i << 1; } msDelta = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond - msBeforeCount; Debug.Log($"i << 1 took {msDelta}ms"); msBeforeCount = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond; for (int j = 0; j < numberOfIteration; j++) { i = i >> 1; } msDelta = DateTime.Now.Second * 1000 + DateTime.Now.Millisecond - msBeforeCount; Debug.Log($"i >> 1 took {msDelta}ms"); } }

Вкратце, я прогонял операции умножения/деления на 2 и битовые сдвиги влево/вправо на 1 бит по 1 миллиарду раз на каждую операцию и смотрел, сколько миллисекунд займёт их выполнение.

Логи

Получилось, что битовые сдвиги действительно быстрее операций умножения и деления, но не слишком драматично. В паре "сдвиг влево — умножение" разница так вообще была порядка 3%, однако, в паре "сдвиг вправо — деление" различие составляло уже приличные 202%. И это я гонял по миллиарду итераций, в реальном проекте разницу пришлось бы искать с лупой.

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

{ "author_name": "dyst0p", "author_type": "self", "tags": ["csharp"], "comments": 4, "likes": 3, "favorites": 3, "is_advertisement": false, "subsite_label": "unknown", "id": 818118, "is_wide": true, "is_ugc": true, "date": "Wed, 04 Aug 2021 10:03:46 +0300", "is_special": false }
0
4 комментария
Популярные
По порядку

Интересно, какой вариант используют разные студии

1

Думаю, умножение и деление в угоду читаемости кода.
@Andrey Apanasik подтвердишь или опровергнешь?

0

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

Мне кажется, что либо с делением какой-то хитрый косяк, либо во время теста что-то тяжёлое запустилось. По идее последние лет 15 в массовых x86 процессорах и арифметика и сдвиги работаю примерно одинаково.

В коде такие штуки лучше писать так, как понятнее -  в C++ современные компиляторы знают мильон хитрых оптимизаций типа такой и вставляют их в сгенерированный машинный код гораздо лучше среднего программиста. А если тормозит - посмотреть с профилировщиком, что именно и почему. В C# по идее тоже самое.

1

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

Это да, но я-то просто хотел производительность разных операций замерить.
Мне кажется, что либо с делением какой-то хитрый косяк, либо во время теста что-то тяжёлое запустилось

Сейчас попробовал на uint, long, ulong заменить - деление всегда сильно медленнее. Ну, и при операциях на беззнаковых типах деление всегда немного быстрее, чем на знаковых. Я раз по 10 запускал скрипт и в прошлый раз, и сейчас, всегда хорошая кучность результатов.
Прикрепил результаты для long и ulong

0
Читать все 4 комментария
null