Я умело построил таблицу поиска в сборке. На всякий случай, если вы ржавые на вашей сборке,
Процедура ожидает, что параметр будет в регистре ecx
. Я проверяю, что он находится в диапазоне, затем считываю значения таблицы поиска в регистры eax
и edx
. Если значение выходит за пределы диапазона, я просто записываю регистры eax
и edx
вместе с ними (это приводит к их 0). К сожалению, так как это процедура сборки, компилятор не сможет встроить код. Но я уверен, что те немногие циклы, которые я сохранил, написав мою классную процедуру сборки, будут более чем компенсировать любой выигрыш, встроенный.
factorial:
xorl %eax, %eax
xorl %edx, %edx
cmpl $20, %ecx
ja .TOOBIG
movl CSWTCH.1(,%ecx,8), %eax
movl CSWTCH.1+4(,%ecx,8), %edx
.TOOBIG:
LOOKUP_TABLE:
.section .rodata
.align 32
.type CSWTCH.1, @object
.size CSWTCH.1, 168
CSWTCH.1:
.long 1
.long 0
.long 1
.long 0
.long 2
.long 0
.long 6
.long 0
.long 24
.long 0
.long 120
.long 0
.long 720
.long 0
.long 5040
.long 0
.long 40320
.long 0
.long 362880
.long 0
.long 3628800
.long 0
.long 39916800
.long 0
.long 479001600
.long 0
.long 1932053504
.long 1
.long 1278945280
.long 20
.long 2004310016
.long 304
.long 2004189184
.long 4871
.long -288522240
.long 82814
.long -898433024
.long 1490668
.long 109641728
.long 28322707
.long -2102132736
.long 566454140
Таблица поиска сложна в обслуживании, поэтому я включил скрипт, который использовал для ее создания
static constexpr uint64_t const_factorial(uint32_t i) {
return (i==0)? 1: (i * const_factorial(i-1));
}
uint64_t factorial(uint32_t i) {
switch(i) {
case 0: return const_factorial(0);
case 1: return const_factorial(1);
case 2: return const_factorial(2);
case 3: return const_factorial(3);
case 4: return const_factorial(4);
case 5: return const_factorial(5);
case 6: return const_factorial(6);
case 7: return const_factorial(7);
case 8: return const_factorial(8);
case 9: return const_factorial(9);
case 10: return const_factorial(10);
case 11: return const_factorial(11);
case 12: return const_factorial(12);
case 13: return const_factorial(13);
case 14: return const_factorial(14);
case 15: return const_factorial(15);
case 16: return const_factorial(16);
case 17: return const_factorial(17);
case 18: return const_factorial(18);
case 19: return const_factorial(19);
case 20: return const_factorial(20);
default: return 0;
}
}
На всякий случай, если вы пропустили это из-за моей неудачной попытки юмора. Компилятор C ++ более чем способен правильно оптимизировать ваш код. Как вы можете видеть, мне не нужно было ничего делать с таблицами поиска, бинарными деревьями поиска или хэшами. Просто простое выражение switch
, а остальное сделал компилятор.