Стоимость конвертации - PullRequest
2 голосов
/ 23 апреля 2019

Позвольте мне сначала объяснить причину проблемы, которую я изложу.У меня есть вектор v слов без знака с информацией, хранящейся в битах, а также слово w некоторого, возможно, другого типа без знака.Я хотел бы поместить len бит из v в w, начиная с i th LSB w.Например, рассмотрим нижеприведенный случай, когда я представлял слова в виде битов только для пояснения.

T1 w = 10110100;
vector<T2> v = [11, 00, 10, 01];
T1 len = 5;
T1 start = 2;
T1 dst_digits = 8;
T1 src_digits = 2;

10110100 -> 10111100 -> 10001100 -> 11001100 

Понятно, что нам нужно будет перебрать v и добавить биты к w одно слово за раз.Один из способов сделать это - следующий

template<class T>
T _blend(T a, T b, T start, T len) {
    // Replaces len bits of a by the ones of b starting at start
}

auto it = std::begin(v);
while (len > 0) {
    w = _blend(w, 
               (T1) ((T1) *first) << start), 
               start,
               std::min(len, src_digits)
               );
    start += std::min(len, src_digits);
    ++first;
    len -= std::min(len, src_digits);
}

Я довольно новичок в C ++, и приведенный выше код является упрощенным кодом, но основная идея остается в силе.У меня это работает и сейчас.Тем не менее, я считаю (T1) ((T1) *first) << start) безобразнымЕсли я не включу первое приведение, операция сдвига будет переведена в int или long, а затем будет несовместима с другими типами _blend.Если я не включу второй актерский состав, я могу превышение *first (в случае, когда dst_digits > src_digits и start > src_digits).

Теперь мой вопрос: насколько дорогодва (T1) преобразования?Мое предположение не так дорого, как другие вещи, такие как вызов std::min или другие операторы в цикле.Я спрашиваю только потому, что, исходя из Python, видеть что-то вроде (T1) ((T1) *first) << start) выглядит просто неестественно, и мне интересно, является ли это просто следствием C ++ с минимальными накладными расходами или нет, и есть ли просто лучший способ сделать это?это.

1 Ответ

1 голос
/ 23 апреля 2019

В системе с прямым порядком байтов преобразование целого числа без знака в целое число без знака преобразуется в ноль или одну инструкцию.

Если в rax есть uint64, то приведение к uint32 в основном не работает. Компилятор просто предположит, что значение находится в eax (наименее значимая половина rax).

Если в eax есть uint32, то приведение к uint64 - это всего лишь одна очень быстрая инструкция. Компилятор обнуляет (заполняет наиболее значительную часть нулями) значение в eax и помещает результат в rbx с помощью инструкции movzx.

Неподписанные целочисленные приведения - наименьшая ваша проблема во время этой операции. Возможно, вы захотите использовать std::vector<bool> или std::bitset, так как они сделают это немного за вас.

...