Быстрый расчет расстояния Хэмминга в C

я читал статью Википедии на Вес Хэмминга и заметил кое-что интересное:

таким образом эквивалентно Hamming distance из строки all-zero одинаковой длины. Для наиболее типичного случая, строка битов, это число 1 в строке. В этом двоичный случай, он также называется количеством населения,popcount или в сторону Сум.

[акцент мой]

так что мне кое-что пришло в голову. Могу ли я вычислить расстояние Хэмминга между двумя строками по XORing их, а затем принимая вес Хэмминга (POPCOUNT) результирующей строки?

что-то в этом роде (используя gcc intrinsics):

#include <stdint.h>

int hammingDistance (uint64_t x, uint64_t y) {
        uint64_t res = x ^ y;
        return __builtin_popcountll (res);
}

теперь, что касается того, почему я хотел бы сделать это, ну, на некоторых платформах, да, это было просто переводить gcc испускание вызова функции, которая вычисляет popcount. Например, на x64 без popcnt, gcc выплевывает (GODBOLT's GCC Online):

hammingDistance:
    sub rsp, 8
    xor rdi, rsi
    call    __popcountdi2
    add rsp, 8
    ret

OTOH, если у вас есть платформа, поддерживающая POPCOUNT, например модели x64, включая nehalem и после (которые POPCNT), вы получаете (GODBOLT's GCC Online):

hammingDistance:
    xor rdi, rsi
    popcnt  rax, rdi
    ret

который должен быть waaay быстрее, особенно после ввода.


Но вернемся к изначальному вопросу. Можешь взять Хэмминг? Вес XOR двух строк, чтобы найти их расстояние Хэмминга? т. е.:

HD = HW (x xor y)

2 ответов


расстояние Хэмминга между двумя строками равной длины,x и y, определяется как количество позиций, в которых они отличаются. В случае x и y будучи bitstrings, x^y является строкой с 1s в точно положениях они отличаются. Таким образом, HammingDistance(x,y) = Number of 1s in x^y, для bitstrings. Кроме того,HammingWeight(x) = number of 1s in x для bitstring x. Таким образом, ваше первое требование,HammingDistance(x,y) = HammingWeight(x^y) верно для bitstrings. Установив это, ясно, что ваша реализация верна.


Да, это работает. Для каждого бита, бит равен 1, если и только если входные биты различны. Следовательно, применительно к целому битовому вектору результат имеет столько же битов (HW), сколько входы имеют разные биты (HD). И ваш код, похоже, отлично использует эти отношения. Фактически, этот ярлык даже упоминается далее в статье веса Хэмминга, на которую вы ссылаетесь (эффективная реализация):

расстояние Хэмминга двух слов A и B может быть вычисляется как вес Хэмминга xor B.