В ответе на главный вопрос неверный оператор сдвига? - PullRequest
4 голосов
/ 13 июля 2020

В следующем вопросе: Почему обработка отсортированного массива выполняется быстрее, чем обработка несортированного массива? принятый ответ объясняет способ избежать предсказания ветвления для данного примера. Он / она заменяет условный оператор некоторыми побитовыми операторами:

Заменить:

if (data[c] >= 128)
    sum += data[c];

на:

int t = (data[c] - 128) >> 31;
sum += ~t & data[c];

однако , в строке, где он сдвигается вправо, он, кажется, делает это с потенциально подписанным значением, которое, согласно этому:

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

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

1 Ответ

4 голосов
/ 13 июля 2020

Если data[c] >= 128, то data[c] - 128 будет неотрицательным, поэтому бит знака будет 0. В противном случае, если data[c] < 128, то data[c] - 128 будет отрицательным, поэтому его бит знака будет 1.

Если мы сдвинемся вправо на 31 (при условии, что int составляет 32 бита, а сдвиг вправо являются arithmeti c, так что да, реализация определена, но довольно распространена), тогда у нас будет либо 0x00000000, когда data[c] >= 128, либо 0xffffffff, когда data[c] < 128.

Если мы затем поразрядно инвертируем это значение, тогда у нас будет либо 0xffffffff, когда data[c] >= 128, либо 0x00000000, когда data[c] < 128.

Если мы поразрядно И это значение с data[c], тогда у нас будет либо data[c], когда data[c] >= 128 или 0x00000000, если data[c] < 128.

Добавление 0 к sum ничего не делает, поэтому мы фактически добавляем только значения, которые больше или равны 128 без ветвления.

...