LINUX.ORG.RU

[C] shift with zero fill.

 


0

1

Мне нужен побитовый сдвиг вправо.

Сдвиг делается над 32-битным unsigned.

Если кол-во битов для сдвига >= 32 выдает не 0. А нужен 0.

Нагуглил, что здесь undefined behaviour. Пока решил проблему вот так:

if (value_shift > 31)
{
  return 0;
}
return value >> value_shift;

Каким макаром можно сделать тоже самое, но без if?

★★

Последнее исправление: vladimir-vg (всего исправлений: 2)

Каким макаром можно сделать тоже самое, но без if?

Например, делением на 2**value_shift :)

power
()

(!(shift - shift%32)) * (value >> shift)

(не знаю, во что компилируется "!", и всегда ли !0 == 1)

Если известны ограничения на размер shift, например, shift < 64, то

(1-(shift/32)) * (value >> shift);
ttnl ★★★★★
()

> Сдвиг делается над 32-битным unsigned.

Если кол-во битов для сдвига >= 32 выдает не 0.

А что выдаёт?

Sorcerer ★★★★★
()
Ответ на: комментарий от Sorcerer

>>Нагуглил, что здесь undefined behaviour.

Сдвиг делается над 32-битным unsigned. > Если кол-во битов для сдвига >= 32 выдает не 0.


А что выдаёт?


Читать-то умеете?

Dimanc ★★
()

> Каким макаром можно сделать тоже самое, но без if?

?: ;)

зы: что за процессор и какой диапазон value_shift?

arsi ★★★★★
()
Ответ на: комментарий от ttnl

> А что выдаёт?

Выдаёт значение, как если бы value_shift был взят по модулю 32.

зы: что за процессор и какой диапазон value_shift?

Процессор x86. Интересны в первую очередь переносимые варианты.

(!(shift - shift%32)) * (value >> shift)

Спасибо, попробую.

vladimir-vg ★★
() автор топика
Ответ на: комментарий от vladimir-vg

в общем случае от условия убежать не получится. !(…) — тоже ветвление, с условным присваиванием или переходом.

так что приведённый в стартовом посте пример и есть лучшее решение. если нужно сократить количество строк, то можно записать так:

для unsigned value_shift:

return value_shift > 31 ? 0 : value >> value_shift;

или, если value_shift может быть отрицательным:

return value_shift & ~31 ? 0 : value >> value_shift;

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

зы: на последний вариант для х86_64 gcc-4.5.1 генерит более оптимальный код, чем icc-11.1 :)

arsi ★★★★★
()
Ответ на: комментарий от arsi

> если нужно сократить количество строк, то можно записать так:

Гыгы. Я скорее наоборот, не скуплюсь.

или, если value_shift может быть отрицательным:

value_shift : uint32_t

зы: на последний вариант для х86_64 gcc-4.5.1 генерит более оптимальный код, чем icc-11.1 :)

А как определяется оптимальность? Слышал, что даже меньшее кол-во инструкций может выполнятся медленней. Вроде как у icc есть особая voodoo-магия, учитывающая более тонкости реализации своих процессоров.

Но это так, с чужих слов.

vladimir-vg ★★
() автор топика
Ответ на: комментарий от vladimir-vg

> (!(shift - shift%32)) * (value >> shift)

Звиняюсь, вместо первой скобки надо !(shift>>5)...

Если генерирует операторы перехода, то плохо конечно

ttnl ★★★★★
()
Ответ на: комментарий от vladimir-vg

> А как определяется оптимальность?

визуально, по objdump -d :) icc добавил явно лишний mov.

провёл тест… но как толково протестировать, когда варианты отличаются на ±1 такт? :)

gcc — 1m55.869s, icc — 2m0.437s (это user). кроме того, проверял на amd64, а не на intel64…

arsi ★★★★★
()
Ответ на: комментарий от arsi

>icc — 2m0.437s (это user). кроме того, проверял на amd64, а не на intel64…

icc разве не определяет процессор и выбирает оптимальный код только для intel? //где-то здесь пробегал слух, я не знаю, как на самом деле

Dimanc ★★
()
Ответ на: комментарий от Dimanc

да в любом случае icc «недооптимизировал» ;)

icc (-O2):

   0:   33 d2                   xor    %edx,%edx
   2:   89 f1                   mov    %esi,%ecx
   4:   d3 ef                   shr    %cl,%edi
   6:   f7 c6 e0 ff ff ff       test   $0xffffffe0,%esi
   c:   0f 45 fa                cmovne %edx,%edi
   f:   89 f8                   mov    %edi,%eax
  11:   c3                      retq

gcc (-O2):

   0:   89 f1                   mov    %esi,%ecx
   2:   31 c0                   xor    %eax,%eax
   4:   d3 ef                   shr    %cl,%edi
   6:   83 e6 e0                and    $0xffffffffffffffe0,%esi
   9:   0f 44 c7                cmove  %edi,%eax
   c:   c3                      retq

если уж test так сильно круче and, то мог бы примерно так скомпилить:

mov    %esi,%ecx
xor    %eax,%eax
shr    %cl,%edi
test   $0xffffffe0,%esi
cmove  %edi,%eax
retq

т.е. –1 mov и –1 промежуточный регистр (edx).

arsi ★★★★★
()

Скастуй в 64 бита, сдвинь и скастуй обратно.

Yareg ★★★
()

Обосраться сколько тут воннаби оптимизаторов собралось.

Профайлер в руки взять пробовали?

Love5an
()

Сколько на ЛОРе недопрограммистов ...

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.