Fonction de code machine x86-64, 40 octets.
Ou 37 octets si 0 ou non-zéro est autorisé comme "vérité", comme strcmp.
Grâce à la réponse C de Karl Napf pour l’idée bitmap, ce que x86 peut faire de manière très efficace avec BTS .
Signature de fonction:, _Bool cube_digits_same(uint64_t n);
à l’aide de l’ABI System V x86-64. ( n
en RDI, valeur de retour booléen (0 ou 1 en AL)).
_Bool
est défini par ISO C11 et est généralement utilisé #include <stdbool.h>
pour définir bool
avec la même sémantique que C ++ bool
.
Potentiel d'économies:
- 3 octets: retour de la condition inverse (différent de zéro s'il y a une différence). Ou depuis inline asm: retour d'une condition de drapeau (ce qui est possible avec gcc6)
- 1 octet: Si nous pouvions supprimer EBX (cela donnerait à cette fonction une convention d'appel non standard). (pourrait le faire depuis inline asm)
- 1 octet: l'instruction RET (de inline asm)
Tout cela est possible s'il s'agissait d'un fragment inline-asm au lieu d'une fonction, ce qui en ferait 35 octets pour 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 semble être le moyen le plus simple de répéter une fois. J'ai aussi regardé simplement répéter la boucle (sans les préfixes REX et un registre bitmap différent), mais c'est légèrement plus grand. J'ai également essayé d'utiliser PUSH RSI et d'utiliser test spl, 0xf
/ jz
to en boucle une fois (étant donné que l'ABI exige que RSP soit 16B aligné avant CALL, une poussée l'aligne et une autre l'aligne à nouveau). Il n'y a pas d' test r32, imm8
encodage, le plus petit moyen était donc d'utiliser une instruction 4B TEST (incluant un préfixe REX) pour tester uniquement l'octet de poids faible de RSP par rapport à un imm8. Même taille que LEA + LOOP, mais avec les instructions supplémentaires PUSH / POP requises.
Testé pour tous les n de la plage de test, par rapport à la mise en œuvre C de steadybox (car elle utilise un algorithme différent). Dans les deux cas de résultats différents que j'ai examinés, mon code était correct et celui de steadybox, celui qui était incorrect. Je pense que mon code est correct pour tout 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);
}
}
Les seules lignes imprimées ont c = 1 asm = 0: faux positifs pour l'algorithme C.
Également testé sur une uint64_t
version de l'implémentation C de Karl du même algorithme, et les résultats correspondent pour toutes les entrées.