funzione codice macchina x86-64, 40 byte.
O 37 byte se 0 rispetto a zero è consentito come "verità", come strcmp.
Grazie alla risposta C di Karl Napf per l'idea bitmap, che x86 può fare in modo molto efficiente con BTS .
Firma della funzione:, _Bool cube_digits_same(uint64_t n);
utilizzando l'ABI System V x86-64. ( n
in RDI, valore di ritorno booleano (0 o 1) in AL).
_Bool
è definito da ISO C11 ed è in genere utilizzato #include <stdbool.h>
per definire bool
con la stessa semantica di C ++ bool
.
Potenziali risparmi:
- 3 byte: restituzione della condizione inversa (diversa da zero se c'è una differenza). O da inline asm: restituire una condizione di bandiera (che è possibile con gcc6)
- 1 byte: se potessimo ostruire EBX (farlo darebbe a questa funzione una convenzione di chiamata non standard). (potrebbe farlo da inline asm)
- 1 byte: l'istruzione RET (da inline asm)
Tutti questi sono possibili se questo fosse un frammento inline-asm invece di una funzione, che lo renderebbe 35 byte per 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 sembra il modo più piccolo di ripetere una volta. Ho anche guardato solo ripetendo il ciclo (senza prefissi REX e un registro bitmap diverso), ma è leggermente più grande. Ho anche provato a usare PUSH RSI e usare test spl, 0xf
/ jz
per eseguire il loop una volta (poiché l'ABI richiede che RSP sia allineato di 16B prima di CHIAMATA, quindi una spinta la allinea e un'altra disallinea di nuovo). Non c'è test r32, imm8
codifica, quindi il modo più piccolo era con un'istruzione TEST 4B (incluso un prefisso REX) per testare solo il byte basso di RSP su un imm8. Stesse dimensioni di LEA + LOOP, ma con istruzioni PUSH / POP extra richieste.
Testato per tutte le n nell'intervallo di test, rispetto all'implementazione C di steadybox (poiché utilizza un algoritmo diverso). Nei due casi di risultati diversi che ho visto, il mio codice era corretto e quello di steadybox era sbagliato. Penso che il mio codice sia corretto per tutti 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);
}
}
Le uniche righe stampate hanno c = 1 asm = 0: falsi positivi per l'algoritmo C.
Testato anche contro una uint64_t
versione dell'implementazione C di Karl dello stesso algoritmo e i risultati corrispondono per tutti gli input.