função de código de máquina x86-64, 40 bytes.
Ou 37 bytes, se 0 vs. diferente de zero for permitido como "verdade", como strcmp.
Graças à resposta C de Karl Napf para a idéia de bitmap, que o x86 pode fazer de maneira muito eficiente com o BTS .
Assinatura da função:, _Bool cube_digits_same(uint64_t n);
usando o x86-64 System V ABI. ( n
em RDI, valor de retorno booleano (0 ou 1) em AL).
_Bool
é definido pela ISO C11 e normalmente é usado #include <stdbool.h>
para definir bool
com a mesma semântica que o C ++ bool
.
Potencial de economia:
- 3 bytes: retornando a condição inversa (diferente de zero, se houver alguma diferença). Ou do asm inline: retornando uma condição de flag (possível com o gcc6)
- 1 byte: se pudéssemos derrotar o EBX (isso daria a essa função uma convenção de chamada não padrão). (poderia fazer isso de inline asm)
- 1 byte: a instrução RET (do inline asm)
Tudo isso é possível se esse fosse um fragmento inline-asm em vez de uma função, o que tornaria 35 bytes para 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 parece ser a menor maneira de repetir uma vez. Também observei apenas a repetição do loop (sem prefixos REX e um registro de bitmap diferente), mas isso é um pouco maior. Eu também tentei usar PUSH RSI e usar test spl, 0xf
/ jz
para fazer loop uma vez (uma vez que a ABI exige que o RSP seja 16B alinhado antes de CALL, então um empurrão o alinha e outro desalinha novamente). Não há test r32, imm8
codificação; portanto, a menor maneira foi com uma instrução 4B TEST (incluindo um prefixo REX) para testar apenas o byte baixo do RSP contra um imm8. Mesmo tamanho que LEA + LOOP, mas com instruções extras de PUSH / POP necessárias.
Testado para todos os n na faixa de teste, em comparação à implementação C do stablebox (já que ele usa um algoritmo diferente). Nos dois casos de resultados diferentes para os quais eu olhei, meu código estava correto e o do stablebox estava errado. Eu acho que meu código está correto para todos os 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);
}
}
As únicas linhas impressas têm c = 1 asm = 0: falso-positivos para o algoritmo C.
Também testado contra uma uint64_t
versão da implementação C de Karl do mesmo algoritmo, e os resultados correspondem a todas as entradas.