Установка диапазона битов по порядковому номеру - PullRequest
0 голосов
/ 25 марта 2012

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

void MaskAddRange(UINT& mask, UINT first, UINT count)
{
    mask |= ((1 << count) - 1) << first;
}

Однако, как выяснилось, он не работал правильно для count = 32. Результатом 1 << count в таком случае теоретически является неопределенное поведение (или результат), а практически на x86 - 1, поскольку операнд сдвига обрабатывается по модулю 32.

Я хочу исправить это выражение для корректной работы и в этом крайнем случае. Какой самый простой / красивый / эффективный способ сделать это?

Работа с этим конкретным случаем с помощью ветвления (if, ?) довольно проста, хотя и уродлива, и, держу пари, она также неэффективна.

Другой способ - повысить операнд сдвига до большего типа (64 бита). Я имею в виду следующее:

void MaskAddRange(UINT& mask, UINT first, UINT count)
{
    mask |= (UINT(unsigned __int64(1) << count) - 1) << first;
}

Есть ли лучший способ?

Ответы [ 2 ]

1 голос
/ 25 марта 2012

Никогда не думайте, что что-то неэффективно, если вы не можете это доказать.С другой стороны, if-else может быть более эффективным на вашей архитектуре + ОС, чем переход на 64-битную версию.Я не думаю, что есть какой-то другой, вменяемый подход, кроме тех, которые вы уже опубликовали.

Я бы пошел на if-else, потому что он документирует намерение обработать крайний случай,Повышение до 64-битной не указывает на это намерение.

0 голосов
/ 25 марта 2012

Вы можете использовать

mask |= (UINT(-1)<<first) & (UINT(-1)>>(32-first-count))

, который является более сложным, но должен работать в любом случае.Эффективность этого выражения по отношению к другим решениям может зависеть от архитектуры и компилятора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...