x86-64 기계 코드 기능, 40 바이트.
또는 0과 0이 아닌 값이 strcmp와 같이 "truthy"로 허용되는 경우 37 바이트입니다.
비트 맵 아이디어에 대한 Karl Napf의 C 답변 덕분에 x86은 BTS로 매우 효율적으로 작업 할 수 있습니다 .
기능 서명 : _Bool cube_digits_same(uint64_t n);
, x86-64 System V ABI 사용. ( n
RDI에서 부울 리턴 값 (0 또는 1)은 AL).
_Bool
는 ISO C11에 의해 정의되며 일반적 으로 C ++과 동일한 의미로 #include <stdbool.h>
정의 bool
하는 데 사용됩니다 bool
.
잠재적 절감 :
- 3 바이트 : 역 조건 반환 (차가있는 경우 0이 아님). 또는 인라인 asm에서 : 플래그 조건 반환 (gcc6에서 가능)
- 1 바이트 : EBX를 클로버 할 수 있다면 (이 기능은 비표준 호출 규칙을 제공합니다). (인라인 asm에서 그렇게 할 수 있음)
- 1 바이트 : RET 명령어 (인라인 asm에서)
이것이 함수가 아닌 인라인 -asm 프래그먼트 인 경우 모두 가능하며, 이는 inline-asm의 경우 35 바이트가 됩니다.
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.
루프는 한 번 반복하는 가장 작은 방법 인 것 같습니다. 또한 루프 (REX 접두사와 다른 비트 맵 레지스터가없는)를 반복하는 것을 보았지만 약간 더 큽니다. 또한 PUSH RSI를 사용하고 test spl, 0xf
/ jz
를 한 번 반복 하여 시도했습니다 (ABI는 RSP가 CALL 전에 16B로 정렬되어야하므로 한 번 누르면 정렬하고 다시 한 번 잘못 정렬하므로). 아무 없다 test r32, imm8
인코딩되므로 작은 방법은 IMM8 RSP에 대해 단지 낮은 바이트를 테스트하기 위해 (a REX 접두사 포함)도 4b TEST 명령으로했다. LEA + LOOP와 동일한 크기이지만 추가 PUSH / POP 명령이 필요합니다.
steadybox의 C 구현에 대해 테스트 범위의 모든 n에 대해 테스트되었습니다 (다른 알고리즘을 사용하기 때문에). 내가 본 다른 결과의 두 가지 경우에, 내 코드는 정확하고 steadybox는 잘못되었습니다. 내 코드가 모든 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 = 1 asm = 0 : C 알고리즘에 대한 위양성이 있습니다.
또한 uint64_t
동일한 알고리즘의 Karl C 구현 버전에 대해 테스트 했으며 모든 입력에 대해 결과가 일치합니다.