Кращий випадок 8 циклів, найгірший - 12 циклів
Оскільки це не зрозуміло в питанні, я базую це затримки з мосту Плюща.
Підхід тут полягає у використанні інструкції 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 н . Наприклад, для входів у діапазоні 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
за допомогою необхідної постійної. Імовірно, це виграє, якби це був конкурс [тег: інструкція: гольф]. Але FYL2X
має затримку 90-106 для Ivy Bridge.
Бінарний пошук із жорстким кодом. Це насправді може бути конкурентоспроможним - це я залишу комусь іншому :)
Повна таблиця пошуку результатів. Це, я впевнений, теоретично найшвидший, але знадобиться таблиця пошуку 1 ТБ - ще не практична - можливо, через кілька років, якщо закон Мура буде продовжувати діяти.