최상의 경우 8주기, 최악의 경우 12주기
질문에 명확하지 않기 때문에 이것을 Ivy Bridge 대기 시간을 기반으로합니다.
여기서의 접근 방식은 bsr
(비트 스캔 역) 명령을 가난한 사람의 log2 ()로 사용하는 것입니다. 결과는 비트 0에서 42까지의 항목을 포함하는 점프 테이블의 인덱스로 사용됩니다. 64 비트 데이터에 대한 작업이 암시 적으로 필요하다고 가정하면 bsr
명령 사용이 정상입니다.
최상의 경우 입력 가능한 점프 테이블 항목은 bsr
결과를 크기에 직접 매핑 할 수 있습니다 . 예를 들어 32-63 범위의 입력의 bsr
경우 결과는 5이며 1의 크기로 매핑됩니다.이 경우 명령 경로는 다음과 같습니다.
Instruction Latency
bsrq 3
jmp 2
movl 1
jmp 2
total 8
최악의 경우 입력 bsr
결과는 두 가지 가능한 크기로 매핑되므로 점프 가능 항목은 cmp
입력이> 10 n 인지 확인하기 위해 추가 로 하나 를 수행 합니다. 예를 들어 64-127 범위의 입력의 bsr
경우 결과는 6입니다. 해당 점프 테이블 항목은 입력> 100인지 확인하고 그에 따라 출력 크기를 설정합니다.
최악의 경우 경로 외에도에 사용할 64 비트 즉시 값을로드하는 추가 mov 명령이 cmp
있으므로 최악의 경우 경로는 다음과 같습니다.
Instruction Latency
bsrq 3
jmp 2
movabsq 1
cmpq 1
ja 2
movl 1
jmp 2
total 12
코드는 다음과 같습니다.
/* Input is loaded in %rdi */
bsrq %rdi, %rax
jmp *jumptable(,%rax,8)
.m0:
movl $0, %ecx
jmp .end
.m0_1:
cmpq $9, %rdi
ja .m1
movl $0, %ecx
jmp .end
.m1:
movl $1, %ecx
jmp .end
.m1_2:
cmpq $99, %rdi
ja .m2
movl $1, %ecx
jmp .end
.m2:
movl $2, %ecx
jmp .end
.m2_3:
cmpq $999, %rdi
ja .m3
movl $2, %ecx
jmp .end
.m3:
movl $3, %ecx
jmp .end
.m3_4:
cmpq $9999, %rdi
ja .m4
movl $3, %ecx
jmp .end
.m4:
movl $4, %ecx
jmp .end
.m4_5:
cmpq $99999, %rdi
ja .m5
movl $4, %ecx
jmp .end
.m5:
movl $5, %ecx
jmp .end
.m5_6:
cmpq $999999, %rdi
ja .m6
movl $5, %ecx
jmp .end
.m6:
movl $6, %ecx
jmp .end
.m6_7:
cmpq $9999999, %rdi
ja .m7
movl $6, %ecx
jmp .end
.m7:
movl $7, %ecx
jmp .end
.m7_8:
cmpq $99999999, %rdi
ja .m8
movl $7, %ecx
jmp .end
.m8:
movl $8, %ecx
jmp .end
.m8_9:
cmpq $999999999, %rdi
ja .m9
movl $8, %ecx
jmp .end
.m9:
movl $9, %ecx
jmp .end
.m9_10:
movabsq $9999999999, %rax
cmpq %rax, %rdi
ja .m10
movl $9, %ecx
jmp .end
.m10:
movl $10, %ecx
jmp .end
.m10_11:
movabsq $99999999999, %rax
cmpq %rax, %rdi
ja .m11
movl $10, %ecx
jmp .end
.m11:
movl $11, %ecx
jmp .end
.m11_12:
movabsq $999999999999, %rax
cmpq %rax, %rdi
ja .m12
movl $11, %ecx
jmp .end
.m12:
movl $12, %ecx
jmp .end
jumptable:
.quad .m0
.quad .m0
.quad .m0
.quad .m0_1
.quad .m1
.quad .m1
.quad .m1_2
.quad .m2
.quad .m2
.quad .m2_3
.quad .m3
.quad .m3
.quad .m3
.quad .m3_4
.quad .m4
.quad .m4
.quad .m4_5
.quad .m5
.quad .m5
.quad .m5_6
.quad .m6
.quad .m6
.quad .m6
.quad .m6_7
.quad .m7
.quad .m7
.quad .m7_8
.quad .m8
.quad .m8
.quad .m8_9
.quad .m9
.quad .m9
.quad .m9
.quad .m9_10
.quad .m10
.quad .m10
.quad .m10_11
.quad .m11
.quad .m11
.quad .m11_12
.quad .m12
.quad .m12
.quad .m12
.end:
/* output is given in %ecx */
이것은 주로 내가 작성한 개념 증명 C 코드에 대한 gcc 어셈블러 출력에서 생성되었습니다 . C 코드는 계산 가능한 goto를 사용하여 점프 테이블을 구현합니다. 또한 __builtin_clzll()
gcc 내장을 사용하여 명령어로 컴파일됩니다 bsr
(+ xor
).
이 솔루션에 도달하기 전에 몇 가지 솔루션을 고려했습니다.
FYL2X
자연 로그를 계산 한 다음 FMUL
필요한 상수 로 계산합니다 . [tag : instruction : golf] 콘테스트 인 경우 아마도 이길 것입니다. 그러나 FYL2X
아이비 브릿지의 대기 시간은 90-106입니다.
하드 코딩 된 이진 검색. 이것은 실제로 경쟁적 일 수 있습니다-나는 그것을 구현하기 위해 다른 사람에게 맡길 것입니다 :).
전체 검색 결과 표. 이것은 이론적으로 가장 빠르지 만 무어의 법칙이 계속 유지된다면 몇 년 안에 1TB 조회 테이블이 필요합니다.