Функция машинного кода x86-64, 40 байт.
Или 37 байтов, если 0 против ненулевого значения допускается как «правдивый», как strcmp.
Благодаря ответу Карла Напфа на C за идею растрового изображения, которую x86 может сделать очень эффективно с BTS .
Подпись функции: _Bool cube_digits_same(uint64_t n);
с использованием системы x86-64 System V ABI. ( n
в RDI логическое возвращаемое значение (0 или 1) в AL).
_Bool
определяется ISO C11 и обычно используется #include <stdbool.h>
для определения bool
с той же семантикой, что и C ++ bool
.
Потенциальная экономия:
- 3 байта: возвращает обратное условие (ненулевое, если есть разница). Или из встроенного asm: возвращение условия флага (что возможно с gcc6)
- 1 байт: Если бы мы могли перекрыть EBX (это дало бы этой функции нестандартное соглашение о вызовах). (может сделать это из встроенного ассема)
- 1 байт: инструкция RET (из встроенного asm)
Все это возможно, если бы это был фрагмент inline-asm вместо функции, что сделало бы 35 байтов для inline-asm .
0000000000000000 <cube_digits_same>:
0: 89 f8 mov eax,edi
2: 48 f7 e7 mul rdi # can't avoid a REX prefix: 2642245^2 doesn't fit in 32 bits
5: 48 f7 e7 mul rdi # rax = n^3, rdx=0
8: 44 8d 52 0a lea r10d,[rdx+0xa] # EBX would save a REX prefix, but it's call-preserved in this ABI.
c: 8d 4a 02 lea ecx,[rdx+0x2]
000000000000000f <cube_digits_same.repeat>:
f: 31 f6 xor esi,esi
0000000000000011 <cube_digits_same.cube_digits>:
11: 31 d2 xor edx,edx
13: 49 f7 f2 div r10 ; rax = quotient. rdx=LSB digit
16: 0f ab d6 bts esi,edx ; esi |= 1<<edx
19: 48 85 c0 test rax,rax ; Can't skip the REX: (2^16 * 10)^3 / 10 has all-zero in the low 32.
1c: 75 f3 jne 11 <cube_digits_same.cube_digits>
; 1st iter: 2nd iter: both:
1e: 96 xchg esi,eax ; eax=n^3 bitmap eax=n bitmap esi=0
1f: 97 xchg edi,eax ; edi=n^3 bitmap, eax=n edi=n bmp, eax=n^3 bmp
20: e2 ed loop f <cube_digits_same.repeat>
22: 39 f8 cmp eax,edi
24: 0f 94 d0 sete al
;; The ABI says it's legal to leave garbage in the high bytes of RAX for narrow return values
;; so leaving the high 2 bits of the bitmap in AH is fine.
27: c3 ret
0x28: end of function.
LOOP кажется самым маленьким способом повторить один раз. Я также посмотрел на повторение цикла (без префиксов REX и другого регистра растрового изображения), но это немного больше. Я также попытался использовать PUSH RSI и использовать test spl, 0xf
/ jz
для однократной петли (поскольку ABI требует, чтобы RSP был выровнен 16B перед CALL, поэтому одно нажатие выравнивает его, а другое снова выравнивает). test r32, imm8
Кодирования нет , поэтому наименьший путь был с инструкцией 4B TEST (включая префикс REX), чтобы проверить только младший байт RSP против imm8. Тот же размер, что и LEA + LOOP, но с дополнительными инструкциями PUSH / POP.
Проверено для всех n в тестовом диапазоне, по сравнению с реализацией Си от устойчивой среды (поскольку она использует другой алгоритм). В двух случаях, когда я смотрел на разные результаты, мой код был верным, а версионный - неверным. Я думаю, что мой код правильный для всех n.
_Bool cube_digits_same(unsigned long long n);
#include <stdio.h>
#include <stdbool.h>
int main()
{
for(unsigned n=0 ; n<= 2642245 ; n++) {
bool c = f(n);
bool asm_result = cube_digits_same(n);
if (c!=asm_result)
printf("%u problem: c=%d asm=%d\n", n, (int)c, (int)asm_result);
}
}
Единственные напечатанные строки имеют c = 1 asm = 0: ложные срабатывания для алгоритма C.
Также проверен uint64_t
вариант версии того же алгоритма, реализованный Карлом С, и результаты совпадают для всех входных данных.