Альтернативой сдвигу в два раза является переворачивание знака с последующим его вычитанием:
int unpacked = packed & 0x3FF;
int extended = (unpacked ^ 0x200) - 0x200;
Если знак не был установлен, его переворачивание устанавливает его, а вычитание сбрасывает его снова.
Если знак был установлен, его переворачивание сбрасывает его, вычитая, он устанавливает его снова, но также занимает весь путь вверх, устанавливая все биты на этом пути.
Это имеет некоторые преимущества,
- Код не зависит от размера целевого целочисленного типа, если бы
unpacked
и extended
были long
, то то же самое сработало бы. - XOR и вычитание могут быть немного дешевлеНапример, на Skylake вы можете выполнять 4 из этих основных операций за цикл, но только 2 смены.Однако задержка такая же, и она имеет значение, только если доступный ILP в коде высок.
- Сдвиги на самом деле не алгебраически объединяются, но XOR и вычитание могут.Например, если следующая операция заключается в добавлении некоторой константы к
extended
, то это сложение и шаги «вычесть знак» можно объединить в одну операцию.