Trường hợp tốt nhất 8 chu kỳ, trường hợp xấu nhất 12 chu kỳ
Vì không rõ ràng trong câu hỏi, tôi dựa trên cơ sở độ trễ của cầu Ivy.
Cách tiếp cận ở đây là sử dụng bsr
hướng dẫn (quét ngược bit) như log2 () của người nghèo. Kết quả được sử dụng như một chỉ mục trong bảng nhảy chứa các mục nhập cho các bit từ 0 đến 42. Tôi giả sử rằng hoạt động trên dữ liệu 64 bit là hoàn toàn bắt buộc, sau đó sử dụng bsr
hướng dẫn là OK.
Trong trường hợp đầu vào tốt nhất, mục có thể jumptable có thể ánh xạ bsr
kết quả trực tiếp đến độ lớn. ví dụ: Đối với các đầu vào trong phạm vi 32-63, bsr
kết quả sẽ là 5, được ánh xạ tới cường độ 1. Trong trường hợp này, đường dẫn lệnh là:
Instruction Latency
bsrq 3
jmp 2
movl 1
jmp 2
total 8
Trong trường hợp đầu vào tồi tệ nhất, bsr
kết quả sẽ ánh xạ tới hai cường độ có thể, do đó, mục nhập có thể làm được thêm một lần nữa cmp
để kiểm tra xem đầu vào có> 10 n không . Ví dụ: đối với các đầu vào trong phạm vi 64-127, bsr
kết quả sẽ là 6. Mục nhập có thể nhảy tương ứng sau đó kiểm tra xem đầu vào> 100 và đặt cường độ đầu ra tương ứng.
Ngoài đường dẫn trường hợp xấu nhất, chúng tôi có một lệnh Mov bổ sung để tải giá trị tức thời 64 bit để sử dụng trong cmp
, vì vậy đường dẫn lệnh trường hợp xấu nhất là:
Instruction Latency
bsrq 3
jmp 2
movabsq 1
cmpq 1
ja 2
movl 1
jmp 2
total 12
Đây là mã:
/* 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 */
Điều này chủ yếu được tạo ra từ đầu ra trình biên dịch mã gcc cho mã C bằng chứng khái niệm tôi đã viết . Lưu ý mã C sử dụng một goto có thể tính toán để thực hiện bảng nhảy. Nó cũng sử dụng __builtin_clzll()
gcc dựng sẵn, biên dịch theo bsr
hướng dẫn (cộng với một xor
).
Tôi đã xem xét một số giải pháp trước khi đến với giải pháp này:
FYL2X
để tính log tự nhiên, sau đó FMUL
bằng hằng số cần thiết. Điều này có lẽ sẽ giành chiến thắng này nếu nó là một cuộc thi [tag: hướng dẫn: golf]. Nhưng FYL2X
có độ trễ là 90-106 cho cầu Ivy.
Tìm kiếm nhị phân mã hóa cứng. Điều này thực sự có thể cạnh tranh - Tôi sẽ để nó cho người khác thực hiện :).
Hoàn thành bảng tra cứu kết quả. Điều này tôi chắc chắn là nhanh nhất về mặt lý thuyết, nhưng sẽ yêu cầu bảng tra cứu 1TB - chưa thực tế - có thể trong vài năm nữa nếu Định luật Moore tiếp tục giữ.