Chức năng mã máy x86-64, 40 byte.
Hoặc 37 byte nếu 0 so với khác không được phép là "trung thực", như strcmp.
Nhờ câu trả lời C của Karl Napf cho ý tưởng bitmap, x86 có thể thực hiện rất hiệu quả với BTS .
Chữ ký chức năng : _Bool cube_digits_same(uint64_t n);
, sử dụng x86-64 System V ABI. ( n
trong RDI, giá trị trả về boolean (0 hoặc 1) trong AL).
_Bool
được định nghĩa bởi ISO C11 và thường được sử dụng #include <stdbool.h>
để định nghĩa bool
với cùng một ngữ nghĩa như C ++ bool
.
Tiết kiệm tiềm năng:
- 3 byte: Trả về điều kiện nghịch đảo (khác không nếu có sự khác biệt). Hoặc từ mã asm nội tuyến: trả về một điều kiện cờ (có thể với gcc6)
- 1 byte: Nếu chúng ta có thể ghi đè EBX (làm như vậy sẽ cung cấp cho hàm này một quy ước gọi không chuẩn). (có thể làm điều đó từ asm nội tuyến)
- 1 byte: lệnh RET (từ mã asm nội tuyến)
Tất cả những điều này đều có thể nếu đây là một đoạn nội tuyến thay vì một hàm, điều này sẽ tạo ra 35 byte cho nội tuyến-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 dường như là cách nhỏ nhất để lặp lại một lần. Tôi cũng đã xem xét chỉ lặp lại vòng lặp (không có tiền tố REX và một thanh ghi bitmap khác), nhưng nó lớn hơn một chút. Tôi cũng đã thử sử dụng PUSH RSI và sử dụng test spl, 0xf
/ jz
để lặp một lần (vì ABI yêu cầu RSP được căn chỉnh 16B trước CALL, do đó, một lần đẩy sẽ căn chỉnh nó và một lần nữa điều chỉnh lại nó). Không có test r32, imm8
mã hóa, vì vậy cách nhỏ nhất là với lệnh TEST 4B (bao gồm tiền tố REX) để kiểm tra chỉ byte RSP thấp so với số 8. Cùng kích thước với LEA + LOOP, nhưng cần thêm các hướng dẫn PUSH / POP.
Đã thử nghiệm cho tất cả n trong phạm vi thử nghiệm, so với triển khai C của hộp ổn định (vì nó sử dụng thuật toán khác). Trong hai trường hợp kết quả khác nhau mà tôi đã xem xét, mã của tôi là chính xác và ổn định là sai. Tôi nghĩ rằng mã của tôi là chính xác cho tất cả 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);
}
}
Các dòng duy nhất được in có c = 1 asm = 0: false-positive cho thuật toán C.
Cũng đã thử nghiệm với uint64_t
phiên bản triển khai C của Karl cùng một thuật toán và kết quả khớp với tất cả các đầu vào.