stringtranslate.com

Найти первый набор

В программном и аппаратном обеспечении компьютера find first set ( ffs ) или find first one — это битовая операция , которая, учитывая беззнаковое машинное слово , [nb 1] обозначает индекс или позицию младшего значащего бита, установленного на единицу в слове, считая от позиции младшего значащего бита. Почти эквивалентная операция — подсчет конечных нулей ( ctz ) или количество конечных нулей ( ntz ), которая подсчитывает количество нулевых битов, следующих за младшим единичным битом. Дополнительная операция, которая находит индекс или позицию старшего значащего бита набора, — это log base 2 , так называемый потому, что он вычисляет двоичный логарифм ⌊log 2 (x)⌋ . [1] Это тесно связано с подсчетом ведущих нулей ( clz ) или количеством ведущих нулей ( nlz ), которая подсчитывает количество нулевых битов, предшествующих старшему единичному биту. [nb 2] Существует два распространенных варианта find first set: определение POSIX , которое начинает индексацию битов с 1, [2] здесь обозначенное как ffs, и вариант, который начинает индексацию битов с нуля, что эквивалентно ctz и поэтому будет называться так.

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

Примеры

Дано следующее 32-битное слово:

0000 0000 0000 0000 1000 0000 0000 1000

Операция подсчета конечных нулей вернет 3, а операция подсчета ведущих нулей вернет 16. Операция подсчета ведущих нулей зависит от размера слова: если это 32-битное слово усечь до 16-битного слова, операция подсчета ведущих нулей вернет ноль. Операция поиска первого множества вернет 4, что указывает на 4-ю позицию справа. Усеченный логарифм по основанию 2 равен 15.

Аналогично, если задано следующее 32-битное слово, побитовое отрицание приведенного выше слова:

1111 1111 1111 1111 0111 1111 1111 0111

Операция подсчета конечных единиц вернет 3, операция подсчета начальных единиц вернет 16, а операция поиска первых нулей ffz вернет 4.

Если слово равно нулю (биты не установлены), подсчет ведущих нулей и подсчет конечных нулей возвращают количество бит в слове, тогда как ffs возвращает ноль. Реализации find first set как с основанием log 2, так и с основанием log 0 обычно возвращают неопределенный результат для нулевого слова.

Поддержка оборудования

Многие архитектуры включают инструкции для быстрого выполнения find first set и/или связанных операций, перечисленных ниже. Наиболее распространенной операцией является count leading zeros (clz), вероятно, потому, что все другие операции могут быть эффективно реализованы в ее терминах (см. Свойства и отношения).

На некоторых платформах Alpha CTLZ и CTTZ эмулируются программно.

Поддержка инструментов и библиотек

Ряд поставщиков компиляторов и библиотек предоставляют встроенные функции компилятора или библиотечные функции для выполнения операции поиска первого набора и/или связанных с ней операций, которые часто реализуются в терминах приведенных выше аппаратных инструкций:

Свойства и отношения

Если биты помечены, начиная с 1 (что является соглашением, используемым в этой статье), то операции подсчета конечных нулей и поиска первого набора связаны соотношением ctz( x ) = ffs( x ) − 1 (за исключением случаев, когда входные данные равны нулю). Если биты помечены, начиная с 0 , то операции подсчета конечных нулей и поиска первого набора являются абсолютно эквивалентными. При наличии w бит на слово log 2 легко вычисляется из clz и наоборот с помощью log 2 ( x ) = w − 1 − clz( x ) .

Как показано в примере выше, операции поиска первого нуля, подсчета ведущих единиц и подсчета конечных единиц можно реализовать путем отрицания ввода и использования поиска первого набора, подсчета ведущих нулей и подсчета конечных нулей. Обратное также верно.

На платформах с эффективной операцией log 2, таких как M68000, ctz можно вычислить следующим образом:

ctz( x ) = log 2 ( x & −x )

где & обозначает побитовое И, а −x обозначает дополнение x до двух . Выражение x & −x очищает все, кроме младшего значащего бита 1 , так что старший и младший значащие биты 1 одинаковы.

На платформах с эффективной операцией подсчета ведущих нулей, таких как ARM и PowerPC, ffs можно вычислить следующим образом:

ffs( x ) = w − clz( x & −x ) .

И наоборот, на машинах без операторов log 2 или clz , clz можно вычислить с помощью ctz , хотя и неэффективно:

clz = w − ctz(2 ⌈log 2 ( x )⌉ ) (что зависит от ctz, возвращающего w для нулевого входа)

На платформах с эффективной операцией веса Хэмминга (подсчета населения), таких как SPARC POPC[35] [ 36] или Blackfin [37] , ONESсуществует :

ctz( x ) = popcount(( x & −x ) − 1) , [38] [39] или ctz( x ) = popcount(~( x | −x )) ,
ffs( x ) = popcount( x ^ ~− x ) [35]
clz = 32 − popcount(2 ⌈log 2 ( x )⌉ − 1)

где ^ обозначает побитовое исключающее ИЛИ, | обозначает побитовое ИЛИ, а ~ обозначает побитовое отрицание.

Обратную задачу (при заданном i получить x , такой что ctz( x ) = i ) можно вычислить с помощью сдвига влево ( 1 << i ).

Find first set и связанные с ним операции можно расширить до произвольно больших битовых массивов простым способом, начав с одного конца и продолжая до тех пор, пока не встретится слово, которое не является полностью нулевым (для ffs , ctz , clz ) или полностью единичным (для ffz , clo , cto ). Древовидная структура данных, которая рекурсивно использует битовые карты для отслеживания того, какие слова не являются нулевыми, может ускорить этот процесс.

Программная эмуляция

Большинство процессоров, выпущенных в конце 1980-х годов, имеют битовые операторы для ffs или эквивалентов, но некоторые современные, такие как некоторые из серии ARM-Mx, не имеют. Вместо аппаратных операторов для ffs, clz и ctz, программное обеспечение может эмулировать их с помощью сдвигов, целочисленных арифметических и побитовых операторов. Существует несколько подходов в зависимости от архитектуры процессора и, в меньшей степени, семантики языка программирования и качества генерации кода компилятора. Подходы можно в общих чертах описать как линейный поиск , двоичный поиск , поиск+табличный просмотр, умножение де Брейна, преобразование с плавающей точкой/извлечение экспоненты и методы битовых операторов (без ветвлений). Существуют компромиссы между временем выполнения и пространством хранения, а также переносимостью и эффективностью.

Программные эмуляции обычно детерминированы. Они возвращают определенный результат для всех входных значений; в частности, результат для ввода всех нулевых битов обычно равен 0 для ffs и битовой длине операнда для других операций.

Если имеется аппаратный clz или эквивалент, ctz можно эффективно вычислить с помощью битовых операций, но обратное неверно: clz неэффективно вычислять при отсутствии аппаратного оператора.

Функция 2 ⌈log 2 (x)⌉ (округление до ближайшей степени двойки) с использованием сдвигов и побитовых ИЛИ [40] неэффективна для вычисления, как в этом 32-битном примере, и еще более неэффективна, если у нас есть 64-битный или 128-битный операнд:

функция pow2(x): если x = 0 возвращает недействительный // недействительный — это определенная реализация (не в [0,63]) х ← х - 1 для каждого y в {1, 2, 4, 8, 16}: x ← x | (x >> y) вернуть x + 1

ФФС

Поскольку ffs = ctz + 1 (POSIX) или ffs = ctz (другие реализации), можно использовать соответствующие алгоритмы для ctz с возможным конечным шагом добавления 1 к результату и возврата 0 вместо длины операнда для ввода всех нулевых битов.

ЧТЗ

Канонический алгоритм представляет собой цикл, подсчитывающий нули, начиная с младшего бита, пока не встретится единичный бит:

функция ctz1 (x) если x = 0 возвращает w т ← 1 г ← 0 пока (x & t) = 0 т ← т << 1 г ← г + 1 возврат г

Этот алгоритм выполняется за O ( n ) времени и операций и на практике нецелесообразен из-за большого количества условных переходов.

Таблица поиска может исключить большинство ветвей:

таблица[0..2 n -1] = ctz(i) для i из 0..2 n -1 функция ctz2 (x) если x = 0 вернуть w г ← 0 цикл  если (x & (2 n -1)) ≠ 0 вернуть r + table[x & (2 n -1)] х ← х >> н г ← г + н

Параметр n фиксирован (обычно 8) и представляет собой компромисс времени и пространства . Цикл также может быть полностью развернут . Но как линейный поиск этот подход все еще O(n) по количеству бит в операнде.

Реализация бинарного поиска требует логарифмического числа операций и ветвей, как в этой 32-битной версии: [41] [42] Этот алгоритм также может быть реализован с помощью таблицы, заменяющей три нижних оператора «if» на таблицу поиска из 256 записей, используя первый обнаруженный ненулевой байт в качестве индекса.

функция ctz3 (x) если x = 0 возвращает 32 н ← 0 если (x & 0x0000FFFF) = 0: n ← n + 16, x ← x >> 16 если (x & 0x000000FF) = 0: n ← n + 8, x ← x >> 8 если (x & 0x0000000F) = 0: n ← n + 4, x ← x >> 4 если (x & 0x00000003) = 0: n ← n + 2, x ← x >> 2 если (x & 0x00000001) = 0: n ← n + 1 вернуть n

Если оборудование имеет оператор clz, наиболее эффективный подход к вычислению ctz следующий:

функция ctz4 (x) х &= -х вернуть w - (clz(x) + 1)

Алгоритм для 32-битного ctz использует последовательности де Брейна для построения минимальной идеальной хэш-функции , которая устраняет все ветви. [43] [44] Этот алгоритм предполагает, что результат умножения усекается до 32 бит.

для i от 0 до 31: table[ ( 0x077CB531 * ( 1 << i ) ) >> 27 ] ← i // table [0..31] инициализированная функция ctz5 (x) return table[((x & -x) * 0x077CB531) >> 27]

Выражение (x & -x) снова изолирует наименее значимый 1 бит. Тогда есть только 32 возможных слова, которые беззнаковое умножение и сдвиг хэша в правильную позицию в таблице. (Этот алгоритм не обрабатывает нулевой ввод.)

КЛЗ

Канонический алгоритм проверяет один бит за раз, начиная с MSB, пока не будет найден ненулевой бит, как показано в этом примере. Он выполняется за время O(n), где n — это длина бита операнда, и не является практическим алгоритмом для общего использования.

функция clz1 (x) если x = 0 вернуть w т ← 1 << (ж - 1) г ← 0 пока (x & t) = 0 т ← т >> 1 г ← г + 1 возврат г

Улучшение предыдущего подхода к циклированию проверяет восемь бит за раз, а затем использует таблицу поиска записей из 256 (2 8 ) для первого ненулевого байта. Однако этот подход все еще O(n) по времени выполнения.

функция clz2 (x) если x = 0 вернуть w т ← 0xff << (ж - 8) г ← 0 пока (x & t) = 0 т ← т >> 8 г ← г + 8 вернуть r + таблица[x >> (w - 8 - r)]

Двоичный поиск может сократить время выполнения до O(log 2 n):

функция clz3 (x) если x = 0 возвращает 32 н ← 0 если (x & 0xFFFF0000) = 0: n ← n + 16, x ← x << 16 если (x & 0xFF000000) = 0: n ← n + 8, x ← x << 8 если (x & 0xF0000000) = 0: n ← n + 4, x ← x << 4 если (x & 0xC0000000) = 0: n ← n + 2, x ← x << 2 если (x & 0x80000000) = 0: n ← n + 1 вернуть n

Самые быстрые переносимые подходы к моделированию clz — это комбинация двоичного поиска и табличного поиска: 8-битный табличный поиск (2 8 =256 1-байтовых записей) может заменить нижние 3 ветви в двоичном поиске. 64-битные операнды требуют дополнительной ветви. Можно использовать поиск большей ширины, но максимальный практический размер таблицы ограничен размером кэша данных L1 на современных процессорах, который для многих составляет 32 КБ. Сохранение ветви более чем компенсируется задержкой промаха кэша L1 .

Алгоритм, аналогичный умножению де Брейна для CTZ, работает и для CLZ, но вместо того, чтобы изолировать самый старший бит, он округляет до ближайшего целого числа в форме 2 n −1, используя сдвиги и побитовые операции ИЛИ: [45]

таблица[0..31] = {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}функция clz4 (x) для каждого y в {1, 2, 4, 8, 16}: x ← x | (x >> y) return table[((x * 0x07C4ACDD) >> 27) % 32]

Для процессоров с глубокими конвейерами, таких как Prescott и более поздние процессоры Intel, может быть быстрее заменить переходы побитовыми операторами AND и OR (даже если для этого потребуется гораздо больше инструкций), чтобы избежать сброса конвейера для неправильно предсказанных переходов (а эти типы переходов по своей сути непредсказуемы):

функция clz5 (x) г = (х > 0xFFFF) << 4; х >>= г; q = (x > 0xFF ) << 3; x >>= q; r |= q; q = (x > 0xF ) << 2; x >>= q; r |= q; q = (x > 0x3 ) << 1; x >>= q; r |= q; г |= (х >> 1); вернуть г;

На платформах, которые обеспечивают аппаратное преобразование целых чисел в числа с плавающей точкой, поле экспоненты может быть извлечено и вычтено из константы для вычисления количества ведущих нулей. Исправления необходимы для учета ошибок округления. [41] [46] Преобразование чисел с плавающей точкой может иметь существенную задержку. Этот метод крайне непереносим и обычно не рекомендуется.

int x ; int r ; union { unsigned int u [ 2 ]; double d ; } t ;           t . u [ LE ] = 0x43300000 ; // LE равен 1 для little-endian t . u [ ! LE ] = x ; t . d -= 4503599627370496.0 ; r = ( t . u [ LE ] >> 20 ) - 0x3FF ; // log2 r ++ ; // CLZ               

Приложения

Операция подсчета ведущих нулей (clz) может быть использована для эффективной реализации нормализации , которая кодирует целое число как m  × 2 e , где m имеет свой старший бит в известной позиции (например, в самой высокой позиции). Это, в свою очередь, может быть использовано для реализации деления Ньютона-Рафсона , выполнения преобразования целого числа в число с плавающей точкой в ​​программном обеспечении и других приложений. [41] [47]

Подсчет ведущих нулей (clz) можно использовать для вычисления 32-битного предиката "x = y" (ноль, если истина, один, если ложь) с помощью тождества clz(x − y) >> 5 , где ">>" — это беззнаковый сдвиг вправо. [48] Его можно использовать для выполнения более сложных битовых операций, таких как поиск первой строки из n 1 бит. [49] Выражение clz(x − y)1 << (16 − clz(x − 1)/2) является эффективным начальным предположением для вычисления квадратного корня 32-битного целого числа с использованием метода Ньютона . [50] CLZ может эффективно реализовать подавление нулей , быстрый метод сжатия данных , который кодирует целое число как количество ведущих нулевых байтов вместе с ненулевыми байтами. [51] Он также может эффективно генерировать экспоненциально распределенные целые числа, беря clz равномерно случайных целых чисел. [41]

Логарифм по основанию 2 можно использовать для прогнозирования того, произойдет ли переполнение при умножении, поскольку ⌈log 2 (xy)⌉ ≤ ⌈log 2 (x)⌉ + ⌈log 2 (y)⌉ . [52]

Подсчет начальных нулей и подсчет конечных нулей можно использовать вместе для реализации алгоритма обнаружения циклов Госпера [53] , который может найти период функции конечного диапазона, используя ограниченные ресурсы. [42]

Двоичный алгоритм GCD тратит много циклов на удаление конечных нулей; это можно заменить подсчетом конечных нулей (ctz) с последующим сдвигом. Похожий цикл появляется в вычислениях последовательности градин .

Битовый массив может быть использован для реализации очереди приоритетов . В этом контексте find first set (ffs) полезен для эффективной реализации операции "pop" или "pull highest priority element". Планировщик реального времени ядра Linuxsched_find_first_bit() внутренне использует для этой цели. [54]

Операция подсчета конечных нулей дает простое оптимальное решение задачи Ханойской башни : диски нумеруются с нуля, и на шаге k номер диска ctz( k ) перемещается на минимально возможное расстояние вправо (при необходимости возвращаясь налево). Она также может генерировать код Грея , беря произвольное слово и переворачивая бит ctz( k ) на шаге k . [42]

Смотрите также

Примечания

  1. ^ Использование битовых операций с машинным словом, отличным от беззнакового, может привести к неопределенным результатам.
  2. ^ Эти четыре операции также имеют (гораздо реже) отрицательные версии:
    • найти первый ноль ( ffz ), который определяет индекс наименее значимого нулевого бита;
    • подсчет конечных единиц , который подсчитывает количество единичных битов, следующих за наименее значимым нулевым битом.
    • подсчет ведущих единиц , который подсчитывает количество единичных битов, предшествующих самому значимому нулевому биту;
    • найти индекс самого значимого нулевого бита, который является инвертированной версией двоичного логарифма .

Ссылки

  1. ^ Андерсон. Найдите логарифм по основанию 2 целого числа с заданным старшим битом N за O(N) операций (очевидный способ).
  2. ^ ab "FFS(3)". Руководство программиста Linux . Архив ядра Linux . Получено 2012-01-02 .
  3. ^ "Справочник инструкций ARM > Общие инструкции по обработке данных ARM > CLZ". Руководство по ассемблеру ARM Developer Suite . ARM . Получено 2012-01-03 .
  4. ^ "AVR32 Architecture Document" (PDF) (ред. CORP072610). Atmel Corporation . 2011. 32000D–04/201. Архивировано из оригинала (PDF) 2017-10-25 . Получено 2016-10-22 .
  5. ^ ab Alpha Architecture Reference Manual (PDF) . Compaq . 2002. стр. 4-32, 4-34.
  6. ^ ab Руководство разработчика программного обеспечения для архитектур Intel 64 и IA-32. Том 2A. Intel . С. 3-92–3-97.Номер заказа 325383.
  7. ^ Руководство программиста по архитектуре AMD64 Том 3: Общие инструкции и системные инструкции (PDF) . Том 3. Advanced Micro Devices (AMD). 2011. С. 204–205. Номер публикации 24594.
  8. ^ "Руководство программиста по архитектуре AMD64, том 3: инструкции общего назначения и системные инструкции" (PDF) . Технология AMD64 (версия 3.28 ред.). Advanced Micro Devices (AMD). Сентябрь 2019 [2013]. Публикация № 24594. Архивировано (PDF) из оригинала 2019-09-30 . Получено 2014-01-02 .
  9. ^ Руководство разработчика программного обеспечения для архитектуры Intel Itanium. Том 3: Набор инструкций Intel Itanium. Том 3. Intel . 2010. С. 3:38. Архивировано из оригинала 26.06.2019.
  10. ^ ab Архитектура MIPS для программистов. Том II-A: Набор инструкций MIPS32 (редакция 3.02). Технологии MIPS . 2011. стр. 101–102. Архивировано из оригинала 2017-11-07 . Получено 2012-01-04 .
  11. ^ ab Архитектура MIPS для программистов. Том II-A: Набор инструкций MIPS64 (редакция 3.02). Технологии MIPS . 2011. С. 105, 107, 122, 123.
  12. ^ Справочное руководство программиста семейства M68000 (включая инструкции CPU32) (PDF) (редакция 1). Motorola . 1992. стр. 4-43–4-45. M68000PRM/AD. Архивировано из оригинала (PDF) 2019-12-08.
  13. ^ Фрей, Брэд. "Глава 3.3.11 Логические инструкции с фиксированной точкой". PowerPC Architecture Book (версия 2.02 ред.). IBM . стр. 70.
  14. ^ "Глава 3.3.13 Логические инструкции с фиксированной точкой - Глава 3.3.13.1 64-битные логические инструкции с фиксированной точкой". Power ISA версии 3.0B. IBM . стр. 95, 98.
  15. ^ ab Wolf, Clifford (2019-03-22). "RISC-V "B" Bit Manipulation Extension for RISC-V" (PDF) . Github (Draft) (v0.37 ed.) . Получено 2020-01-09 .
  16. ^ Архитектура Oracle SPARC 2011. Oracle . 2011.
  17. ^ Справочное руководство по архитектуре VAX (PDF) . Digital Equipment Corporation (DEC). 1987. стр. 70–71. Архивировано (PDF) из оригинала 29-09-2019 . Получено 09-01-2020 .
  18. ^ abc "Глава 22. Векторные целочисленные инструкции". IBM z/Architecture Principles of Operation (PDF) (Одиннадцатое изд.). IBM . Март 2015. стр. 7-219–22-10. SA22-7832-10. Архивировано из оригинала (PDF) 2020-01-09 . Получено 2020-01-10 .
  19. ^ ab "FFS(3)". Библиотека разработчика Mac OS X. Apple , Inc. 1994-04-19 . Получено 2012-01-04 .
  20. ^ "FFS(3)". Руководство по функциям библиотеки FreeBSD . Проект FreeBSD . Получено 2012-01-04 .
  21. ^ "Другие встроенные функции, предоставляемые GCC". Использование коллекции компиляторов GNU (GCC) . Free Software Foundation, Inc. Получено 14.11.2015 .
  22. ^ "GCC 3.4.0 ChangeLog". GCC 3.4.0 . Free Software Foundation, Inc. Получено 2015-11-14 .
  23. ^ "Clang Language Extensions - chapter Builtin Functions". Команда Clang . Получено 2017-04-09 . Clang поддерживает ряд встроенных библиотечных функций с тем же синтаксисом, что и GCC
  24. ^ "Исходный код Clang". Команда LLVM, Университет Иллинойса в Урбане-Шампейне . Получено 2017-04-09 .
  25. ^ "_BitScanForward, _BitScanForward64". Visual Studio 2008: Visual C++: Встроенные функции компилятора . Microsoft . Получено 2018-05-21 .
  26. ^ "_BitScanReverse, _BitScanReverse64". Visual Studio 2008: Visual C++: Встроенные функции компилятора . Microsoft . Получено 2018-05-21 .
  27. ^ "__lzcnt16, __lzcnt, __lzcnt64". Visual Studio 2008: Visual C++: Встроенные функции компилятора . Microsoft . Получено 2012-01-03 .
  28. ^ "ARM intrinsics". Visual Studio 2012: Visual C++: Compiler Intrinsics . Microsoft . Получено 2022-05-09 .
  29. ^ "Руководство по встроенным компонентам Intel". Intel . Получено 2020-04-03 .
  30. ^ Справочник по внутренним функциям компилятора Intel C++ для Linux. Intel . 2006. стр. 21.
  31. ^ NVIDIA CUDA Programming Guide (PDF) (Версия 3.0 ред.). NVIDIA . 2010. стр. 92.
  32. ^ "'llvm.ctlz.*' Intrinsic, 'llvm.cttz.*' Intrinsic". Справочное руководство по языку LLVM . Инфраструктура компилятора LLVM . Получено 23.02.2016 .
  33. ^ Смит, Ричард (01.04.2020). Рабочий проект N4861, Стандарт языка программирования C++ (PDF) . ISO/IEC. стр. 1150–1153 . Получено 25.05.2020 .
  34. ^ "Стандартный заголовок библиотеки <bit>". cppreference.com . Получено 2020-05-25 .
  35. ^ ab SPARC International, Inc. (1992). "A.41: Population Count. Programming Note" (PDF) . Руководство по архитектуре SPARC: версия 8 (редакция версии 8). Энглвуд Клиффс, Нью-Джерси, США: Prentice Hall . стр. 231. ISBN 978-0-13-825001-0.
  36. ^ Уоррен, младший, Генри С. (2013) [2002]. Hacker's Delight (2-е изд.). Addison Wesley - Pearson Education, Inc. ISBN  978-0-321-84268-8. 0-321-84268-5.
  37. ^ Справочник по набору инструкций Blackfin (предварительное издание). Analog Devices . 2001. С. 8–24. Номер детали 82-000410-14.
  38. ^ Диц, Генри Гордон . "Агрегатные магические алгоритмы". Университет Кентукки . Архивировано из оригинала 2019-10-31.
  39. ^ Айзенберг, Герд (2019-11-03) [2012]. "BitScanProtected". Chess Programming Wiki (CPW) . Архивировано из оригинала 2020-01-09 . Получено 2020-01-09 .
  40. ^ Андерсон. Округлите до следующей большей степени 2.
  41. ^ abcd Уоррен. Глава 5-3: Подсчет начальных нулей.
  42. ^ abc Warren. Глава 5-4: Подсчет конечных нулей.
  43. ^ Лейзерсон, Чарльз Э .; Прокоп, Харальд ; Рэндалл, Кит Х. (1998-07-07). «Использование последовательностей де Брейна для индексации 1 в компьютерном слове» (PDF) . Лаборатория компьютерных наук Массачусетского технологического института, Кембридж, Массачусетс, США. Архивировано (PDF) из оригинала 2020-01-09 . Получено 2020-01-09 .
  44. ^ Буш, Филип (2009-03-01) [2009-02-21]. "Computing Trailing Zeros HOWTO" (PDF) . Архивировано (PDF) из оригинала 2016-08-01 . Получено 2020-01-09 .
  45. ^ Андерсон. Найдите логарифм по основанию 2 N-битного целого числа за O(lg(N)) операций с умножением и поиском.
  46. ^ Андерсон. Найдите целый логарифм по основанию 2 целого числа с 64-битной плавающей точкой IEEE.
  47. ^ Слосс, Эндрю Н.; Саймс, Доминик; Райт, Крис (2004). Руководство разработчика систем ARM по проектированию и оптимизации системного программного обеспечения (1-е изд.). Сан-Франциско, Калифорния, США: Morgan Kaufmann . С. 212–213. ISBN 978-1-55860-874-0.
  48. ^ Уоррен. Глава 2-11: Сравнительные предикаты.
  49. ^ Уоррен. Глава 6-2: Найти первую строку из 1-битов заданной длины.
  50. Уоррен. Глава 11-1: Целочисленный квадратный корень.
  51. ^ Шлегель, Бенджамин; Гемулла, Райнер; Ленер, Вольфганг [на немецком языке] (июнь 2010 г.). «Быстрое целочисленное сжатие с использованием инструкций SIMD». Труды Шестого международного семинара по управлению данными на новом оборудовании . стр. 34–40. CiteSeerX 10.1.1.230.6379 . doi :10.1145/1869389.1869394. ISBN  978-1-45030189-3. S2CID  7545142.
  52. Уоррен. Глава 2-12: Обнаружение переполнения.
  53. ^ Gosper, Bill (апрель 1995) [1972-02-29]. Baker, Henry Givens Jr. (ред.). "Детектор петель". HAKMEM (перепечатанное и преобразованное издание). Кембридж, Массачусетс, США: Лаборатория искусственного интеллекта , Массачусетский технологический институт (MIT). AI Memo 239 Item 132. Архивировано из оригинала 2019-10-08 . Получено 2020-01-09 .
  54. ^ Аас, Джош (2005-02-17). Understanding the Linux 2.6.8.1 CPU Scheduler (PDF) . Silicon Graphics, Inc. (SGI). стр. 19. Архивировано (PDF) из оригинала 2017-05-19 . Получено 2020-01-09 .

Дальнейшее чтение

Внешние ссылки