x86-64-Maschinencodefunktion, 40 Byte.
Oder 37 Bytes, wenn 0 gegen Nicht-Null als "wahr" zulässig ist, wie strcmp.
Vielen Dank an Karl Napfs C-Antwort für die Bitmap-Idee, die x86 mit BTS sehr effizient umsetzen kann .
Funktionssignatur: _Bool cube_digits_same(uint64_t n);
unter Verwendung der x86-64-System-V-ABI. ( n
in RDI boolescher Rückgabewert (0 oder 1) in AL).
_Bool
wird von ISO C11 definiert und wird normalerweise verwendet #include <stdbool.h>
, um bool
mit derselben Semantik wie C ++ zu definieren bool
.
Einsparpotential:
- 3 Bytes: Rückgabe der inversen Bedingung (ungleich Null, wenn ein Unterschied besteht). Oder von inline asm: Rückgabe einer Flagbedingung (was mit gcc6 möglich ist)
- 1 Byte: Wenn wir EBX überlasten könnten (dies würde dieser Funktion eine nicht standardmäßige Aufrufkonvention geben). (könnte das von inline asm machen)
- 1 Byte: der RET-Befehl (von Inline-ASM)
All dies ist möglich, wenn dies ein Inline-Asm-Fragment anstelle einer Funktion wäre, was es für Inline-Asm zu 35 Bytes machen würde .
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 scheint die kleinste Möglichkeit zu sein, sich einmal zu wiederholen. Ich habe mir auch nur das Wiederholen der Schleife angesehen (ohne REX-Präfixe und ein anderes Bitmap-Register), aber das ist etwas größer. Ich habe auch versucht, PUSH RSI und test spl, 0xf
/ jz
zu verwenden, um eine Schleife auszuführen (da das ABI erfordert, dass RSP vor CALL auf 16B ausgerichtet ist, sodass es durch einen Tastendruck ausgerichtet und durch einen anderen erneut falsch ausgerichtet wird). Da es keine test r32, imm8
Codierung gibt, bestand die kleinste Möglichkeit darin, mit einem 4B-TEST-Befehl (einschließlich eines REX-Präfix) nur das Low-Byte von RSP gegen ein imm8 zu testen. Gleiche Größe wie LEA + LOOP, jedoch mit zusätzlichen PUSH / POP-Anweisungen.
Getestet für alle n im Testbereich im Vergleich zur C-Implementierung von steadybox (da ein anderer Algorithmus verwendet wird). In den beiden von mir untersuchten Fällen mit unterschiedlichen Ergebnissen war mein Code korrekt und die von steadybox waren falsch. Ich denke, mein Code ist für alle n korrekt.
_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);
}
}
Die einzigen gedruckten Zeilen haben c = 1 asm = 0: falsch-positiv für den C-Algorithmus.
Wurde auch mit einer uint64_t
Version von Karls C-Implementierung desselben Algorithmus getestet und die Ergebnisse stimmen für alle Eingaben überein.