Используя последовательность де Брюйна, чтобы найти целого числа

11

Шон Андерсон опубликовал немного вертел хаки , содержащие алгоритм Эрика Коула , чтобы найти А.Н. -разрядного целочисленного в операций с умножения и поиска.N v O ( lg ( N ) )log2vNvO(lg(N))

Алгоритм опирается на «магическое» число из последовательности де Брюина. Кто-нибудь может объяснить основные математические свойства последовательности, используемой здесь?

uint32_t v; // find the log base 2 of 32-bit v
int r;      // result goes here

static const int MultiplyDeBruijnBitPosition[32] = 
{
  0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
  8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};

v |= v >> 1; // first round down to one less than a power of 2 
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;

r = MultiplyDeBruijnBitPosition[(uint32_t)(v * 0x07C4ACDDU) >> 27];
Юрий Байда
источник
2
Идея взята из этой статьи supertech.csail.mit.edu/papers/debruijn.pdf . Последовательность де Брюна размера - это способ очень кратко представить все битовые строки размера : каждая возможная строка появляется ровно один раз в виде непрерывной подпоследовательности. Таким образом, если вы сдвинете последовательность де Брейна на бит и прочитаете последние бит, у вас будет уникальный идентификатор для . k n 2 k k n2kkn2kkn
Сашо Николов
1
Кстати, это только вычисляет ; и как написано, он работает только для 32-разрядных целых чисел. log2v
Сашо Николов
1
@Sasho Превратиться в ответ?
Юваль Фильмус
@SashoNikolov Спасибо, добавил к вопросу функцию потолка
Юрий Байда

Ответы:

9

Прежде всего обратите внимание, что этот алгоритм вычисляет только , и, поскольку код написан, он работает только для которые вписываются в битное слово.v 32log2vv32

Последовательность сдвигов и или-s, которая появляется первой, имеет функцию распространения первого 1 бита до самого младшего бита. Численно это дает вам .2 log 2 v - 1v2log2v1

Интересная часть - трюк де Брейна, который взят из этой статьи Лейзерсона, Прокопа и Рэндалла (по-видимому, профессора MIT проводят время, занимаясь немного хаки :)). Что вам нужно знать о последовательностях де Брюина, так это то, что они представляют все возможные последовательности заданной длины таким образом, чтобы это было как можно более сжато. Точно, последовательность де Брейна над алфавитом является двоичной строкой длиной такой, что каждая двоичная строка длины появляется ровно один раз в виде непрерывной подстроки (допускается перенос). Причина, по которой это полезно, состоит в том, что если у вас есть число , битовое представление которого представляет собой последовательность де Брюина (дополненнуюs 2 k k X k k 2 i X i i < k{0,1}s2kkXkнулями), то старшие битов однозначно идентифицируют (до тех пор, пока ).k2iXii<k

Сашо Николов
источник
3
Обратите внимание, что вы можете использовать любую последовательность де Брюина таким образом, чтобы вычислить заданное . Однако вы не можете использовать произвольную последовательность де Брейна для вычисления заданного . Здесь 0x07C4ACDD = 00000111110001001010110011011101, по-видимому, является последовательностью де Брейна с некоторыми дополнительными свойствами, благодаря которой дополнительный не нарушает этот подход. 2 я я 2 я - 1 - 1i2ii2i11
Юкка Суомела
Спасибо @JukkaSuomela, я был немного смущен этим. Я думаю, вы всегда можете просто добавить 1 к хотя. v
Сашо Николов
5

Некоторые комментарии (не совсем ответ). Давайте классифицируем 32-битные целые числа следующим образом:c

  • Тип X: (в виде двоичной строки) является последовательностью Де Брейна (для всех вращений биты [27,31] различны). Пример:c

    11111011100110101100010100100000
    
  • Тип Y: биты [27,31] из различны для . Это то, что Leiserson et al. использование. Примеры:я = 0 , 1 , . , , , 312ici=0,1,...,31

    00000100011001010011101011011111
    00001111101110011010110001010010
    
  • Тип Z: биты [27,31] из различны для . Это то, что нам нужно в исходном вопросе. Примеры:я = 0 , 1 , . , , , 31(2i+11)ci=0,1,...,31

    00000111110001001010110011011101  (07C4ACDD)
    10000111110001001010110011011101
    01111000001110110101001100100011
    11111000001110110101001100100011
    

Некоторые наблюдения, основанные на быстрых экспериментах (надеюсь, я понял это правильно):

  1. Есть 65536 целых чисел типа X.

  2. Есть 4096 целых чисел типа X + Y. Это именно те целые числа типа X, которые начинаются с последовательности '0000 ...'

    • интуиция: с ведущими нулями, вращение = смещение?
  3. Есть 256 целых чисел типа X + Y + Z. Это именно те целые числа типа X, которые начинаются с последовательности «0000011111 ...»

    • интуиция: ??
  4. Все целые числа типа Y также имеют тип X.

  5. Однако есть также 768 целых чисел типа Z, которые не относятся ни к типу X, ни к типу Y. Они начинаются с '1000011111 ...', '0111100000 ...' или '1111100000 ...'

Юкка Суомела
источник
1
Это единственный ответ, который касается того, почему умножение Де Брюина на 2 ^ n-1 работает, а не 2 ^ n, что является просто сдвигом. Я был бы рад, если бы кто-то мог раскрыть «интуицию» №3 выше. Как Эрик Коул придумал это? Методом проб и ошибок? Или какое-то понимание того, что на самом деле происходит с битами при умножении на 2 ^ n-1?
FarmerBob
1
  • Откуда эта константа?

Цитата: «10 декабря 2009 года Марк Дикинсон сбрил пару операций, требуя, чтобы v было округлено до одного меньше следующей степени 2, а не степени 2». [Graphics.stanford.edu/~seander/bithacks.html]

Эта особая константа представляет собой последовательность де Брюина с двоичным алфавитом, но с дополнительным свойством. Я назову это «Свойством Марка Дикинсона», поскольку оригинальный алгоритм может быть реализован без этих специальных последовательностей БД. Добавив 2 дополнительные операции, мы можем использовать любую обычную последовательность БД. Операция: v ^ = (v >> 1); // clr все биты, кроме MSB, установленного после каскадного или сдвига.

  • Результаты (брутфорс)

Seq.Type | Целые числа | № DBSeq. с | без вращений | с Дикинсоном Свойство
B (2, 3) | 256 | 16 | 2 | 1
B (2, 4) | 64 Ки | 256 | 16 | 4
Б (2, 5) | 04Gi | 64 Ки | 02Ки | 256
В (2, 6) | 16Ei | 04Gi | 64Mi | ??

  • Особая собственность

0x7C4ACDD 2 к 12k132 k 1 2 k 1(mod232)32k1введите описание изображения здесь2k- )1

  • Лексикографически наименьшие двоичные последовательности де Брейна со свойством Дикинсона

    [B (2,3): 0x1D] [B (2,4): 0x0F2D] [B (2,5): 0x7C4ACDD] [B (2,6): поиск продолжается]

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

PS Я не освещал конструкцию LUT, которая легко выводится, если вы понимаете принципы работы алгоритмов.

FranG
источник
Наконец найдено: B (2,6) 0x3f08a4c6acb9dbd - 64-битная последовательность де Брейна со свойством Дикинсона. Я нашел как минимум 122К таких последовательностей.
FranG