Наилучший случай 8 циклов, наихудший случай 12 циклов
Поскольку это не ясно в вопросе, я основываю это на задержках Ivy Bridge.
Подход здесь состоит в том, чтобы использовать bsr
(обратное сканирование битов) инструкцию как log2 () бедного человека. Результат используется в качестве индекса в таблице переходов, которая содержит записи для битов от 0 до 42. Я предполагаю, что, учитывая, что операция с 64-битными данными неявно требуется, тогда использование bsr
инструкции в порядке.
В лучшем случае входные данные с помощью таблицы переходов могут отображать bsr
результат непосредственно на величину. Например, для входных данных в диапазоне 32-63, bsr
результат будет 5, который отображается на величину 1. В этом случае путь инструкции:
Instruction Latency
bsrq 3
jmp 2
movl 1
jmp 2
total 8
В наихудших входных данных bsr
результат будет отображаться с двумя возможными значениями, поэтому элемент с перемычкой делает еще одну дополнительную cmp
проверку , чтобы определить, является ли входное значение> 10 n . Например, для входов в диапазоне 64-127 bsr
результат будет 6. Соответствующая запись с перемычкой затем проверяет, является ли вход> 100, и соответственно устанавливает величину выхода.
В дополнение к пути наихудшего случая у нас есть дополнительная инструкция mov для загрузки непосредственного 64-битного значения для использования в cmp
, так что путь инструкции наихудшего случая:
Instruction Latency
bsrq 3
jmp 2
movabsq 1
cmpq 1
ja 2
movl 1
jmp 2
total 12
Вот код:
/* Input is loaded in %rdi */
bsrq %rdi, %rax
jmp *jumptable(,%rax,8)
.m0:
movl $0, %ecx
jmp .end
.m0_1:
cmpq $9, %rdi
ja .m1
movl $0, %ecx
jmp .end
.m1:
movl $1, %ecx
jmp .end
.m1_2:
cmpq $99, %rdi
ja .m2
movl $1, %ecx
jmp .end
.m2:
movl $2, %ecx
jmp .end
.m2_3:
cmpq $999, %rdi
ja .m3
movl $2, %ecx
jmp .end
.m3:
movl $3, %ecx
jmp .end
.m3_4:
cmpq $9999, %rdi
ja .m4
movl $3, %ecx
jmp .end
.m4:
movl $4, %ecx
jmp .end
.m4_5:
cmpq $99999, %rdi
ja .m5
movl $4, %ecx
jmp .end
.m5:
movl $5, %ecx
jmp .end
.m5_6:
cmpq $999999, %rdi
ja .m6
movl $5, %ecx
jmp .end
.m6:
movl $6, %ecx
jmp .end
.m6_7:
cmpq $9999999, %rdi
ja .m7
movl $6, %ecx
jmp .end
.m7:
movl $7, %ecx
jmp .end
.m7_8:
cmpq $99999999, %rdi
ja .m8
movl $7, %ecx
jmp .end
.m8:
movl $8, %ecx
jmp .end
.m8_9:
cmpq $999999999, %rdi
ja .m9
movl $8, %ecx
jmp .end
.m9:
movl $9, %ecx
jmp .end
.m9_10:
movabsq $9999999999, %rax
cmpq %rax, %rdi
ja .m10
movl $9, %ecx
jmp .end
.m10:
movl $10, %ecx
jmp .end
.m10_11:
movabsq $99999999999, %rax
cmpq %rax, %rdi
ja .m11
movl $10, %ecx
jmp .end
.m11:
movl $11, %ecx
jmp .end
.m11_12:
movabsq $999999999999, %rax
cmpq %rax, %rdi
ja .m12
movl $11, %ecx
jmp .end
.m12:
movl $12, %ecx
jmp .end
jumptable:
.quad .m0
.quad .m0
.quad .m0
.quad .m0_1
.quad .m1
.quad .m1
.quad .m1_2
.quad .m2
.quad .m2
.quad .m2_3
.quad .m3
.quad .m3
.quad .m3
.quad .m3_4
.quad .m4
.quad .m4
.quad .m4_5
.quad .m5
.quad .m5
.quad .m5_6
.quad .m6
.quad .m6
.quad .m6
.quad .m6_7
.quad .m7
.quad .m7
.quad .m7_8
.quad .m8
.quad .m8
.quad .m8_9
.quad .m9
.quad .m9
.quad .m9
.quad .m9_10
.quad .m10
.quad .m10
.quad .m10_11
.quad .m11
.quad .m11
.quad .m11_12
.quad .m12
.quad .m12
.quad .m12
.end:
/* output is given in %ecx */
В основном это было сгенерировано из вывода ассемблера gcc для написанного мной кода на языке C для проверки концепции . Обратите внимание, что код C использует вычислимое goto для реализации таблицы переходов. Он также использует __builtin_clzll()
встроенный gcc, который компилируется в bsr
инструкцию (плюс an xor
).
Я рассмотрел несколько решений, прежде чем прийти к этому:
FYL2X
рассчитать натуральный логарифм, затем FMUL
по необходимой константе. Это, вероятно, выиграло бы это, если бы это был конкурс [tag: инструкция: гольф]. Но FYL2X
имеет время ожидания 90-106 для Ivy Bridge.
Жестко закодированный бинарный поиск. Это на самом деле может быть конкурентоспособным - я оставлю это кому-то другому для реализации :).
Полная таблица результатов поиска. Это, я уверен, теоретически самый быстрый, но потребует таблицы поиска в 1 ТБ - пока не практично - возможно, через несколько лет, если закон Мура будет продолжать действовать.