Có một hack (tương đối) nổi tiếng để chia số 32 bit cho ba. Thay vì sử dụng phân chia đắt tiền thực tế, số có thể được nhân với số ma thuật 0x55555556
và 32 bit trên của kết quả là những gì chúng tôi đang tìm kiếm. Ví dụ, đoạn code C sau:Tại sao 0x55555556 chia cho 3 công việc hack?
int32_t div3(int32_t x)
{
return x/3;
}
biên soạn với GCC và -O2
, kết quả trong việc này:
08048460 <div3>:
8048460: 8b 4c 24 04 mov ecx,DWORD PTR [esp+0x4]
8048464: ba 56 55 55 55 mov edx,0x55555556
8048469: 89 c8 mov eax,ecx
804846b: c1 f9 1f sar ecx,0x1f
804846e: f7 ea imul edx
8048470: 89 d0 mov eax,edx
8048472: 29 c8 sub eax,ecx
8048474: c3 ret
Tôi đoán các hướng dẫn sub
có trách nhiệm sửa chữa số âm, bởi vì những gì nó làm về cơ bản là thêm 1 nếu đối số là số âm, và đó là một số NOP
nếu không.
Nhưng tại sao hoạt động? Tôi đã cố gắng nhân các số nhỏ hơn theo cách thủ công với phiên bản 1 byte của mặt nạ này, nhưng tôi không nhìn thấy mẫu và tôi thực sự không thể tìm thấy bất kỳ giải thích nào ở bất kỳ đâu. Nó có vẻ là một số ma thuật bí ẩn có nguồn gốc không rõ ràng cho bất cứ ai, giống như 0x5f3759df.
Ai đó có thể cung cấp giải thích về số học đằng sau điều này không?
Bản sao có thể có của [Phân chia số nguyên nhanh hơn khi mẫu số được biết?] (Http://stackoverflow.com/questions/2616072/faster-integer-division-when-denominator-is-known) –
@PeterO. Xin vui lòng chỉ cho tôi trong câu hỏi đó (hoặc câu trả lời) thuật toán cụ thể mà tôi đã nêu ở trên được giải thích. – szczurcio