fungsi kode mesin x86-64, 40 byte.
Atau 37 byte jika 0 vs non-nol diizinkan sebagai "benar", seperti strcmp.
Berkat jawaban Karl Napf C untuk ide bitmap, yang x86 dapat lakukan dengan sangat efisien dengan BTS .
Fungsi tanda tangan _Bool cube_digits_same(uint64_t n);
:, menggunakan ABI Sistem x86-64. ( n
dalam RDI, nilai pengembalian boolean (0 atau 1) dalam AL).
_Bool
didefinisikan oleh ISO C11, dan biasanya digunakan oleh #include <stdbool.h>
untuk mendefinisikan bool
dengan semantik yang sama dengan C ++ bool
.
Potensi penghematan:
- 3 byte: Mengembalikan kondisi terbalik (bukan nol jika ada perbedaan). Atau dari inline asm: mengembalikan kondisi bendera (yang dimungkinkan dengan gcc6)
- 1 byte: Jika kita bisa mengalahkan EBX (melakukan hal itu akan memberikan fungsi ini konvensi panggilan non-standar). (bisa melakukannya dari inline asm)
- 1 byte: instruksi RET (dari inline asm)
Semua ini dimungkinkan jika ini adalah fragmen inline-asm alih-alih fungsi, yang akan membuatnya 35 byte untuk 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 sepertinya merupakan cara terkecil untuk mengulang sekali. Saya juga melihat hanya mengulangi loop (tanpa awalan REX, dan register bitmap yang berbeda), tapi itu sedikit lebih besar. Saya juga mencoba menggunakan PUSH RSI, dan menggunakan test spl, 0xf
/ jz
untuk loop sekali (karena ABI mensyaratkan bahwa RSP adalah 16B disejajarkan sebelum CALL, jadi satu dorongan menyelaraskannya, dan satu lagi menyelaraskannya lagi). Tidak ada test r32, imm8
pengkodean, jadi cara terkecil adalah dengan instruksi TEST 4B (termasuk awalan REX) untuk menguji hanya byte rendah RSP terhadap imm8. Ukurannya sama dengan LEA + LOOP, tetapi dengan instruksi PUSH / POP tambahan diperlukan.
Diuji untuk semua n dalam rentang tes, vs implementasi C steadybox (karena menggunakan algoritma yang berbeda). Dalam dua kasus hasil berbeda yang saya lihat, kode saya benar dan steadybox salah. Saya pikir kode saya benar untuk semua 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);
}
}
Satu-satunya garis yang dicetak memiliki c = 1 asm = 0: false-positif untuk algoritma C.
Juga diuji terhadap uint64_t
versi implementasi Karl C dari algoritma yang sama, dan hasilnya cocok untuk semua input.