Nguồn câu trả lời của tôi trong:phận Integer 7
Is this expression correct in C preprocessor
tôi là một chút ra khỏi sở trường của tôi ở đây, và tôi đang cố gắng để hiểu làm thế nào các công trình này tối ưu hóa đặc biệt.
Như đã đề cập trong câu trả lời, gcc sẽ tối ưu hóa phân chia số nguyên 7 tới:
mov edx, -1840700269
mov eax, edi
imul edx
lea eax, [rdx+rdi]
sar eax, 2
sar edi, 31
sub eax, edi
Những dịch trở lại vào C như:
int32_t divideBySeven(int32_t num) {
int32_t temp = ((int64_t)num * -015555555555) >> 32;
temp = (temp + num) >> 2;
return (temp - (num >> 31));
}
Chúng ta hãy nhìn vào phần đầu tiên:
int32_t temp = ((int64_t)num * -015555555555) >> 32;
Tại sao lại là số này?
Vâng, hãy lấy 2^64 và chia cho 7 và xem những gì bật ra.
2^64/7 = 2635249153387078802.28571428571428571429
Trông giống như một mớ hỗn độn, điều gì sẽ xảy ra nếu chúng tôi chuyển đổi thành bát phân?
0222222222222222222222.22222222222222222222222
Đó là một mẫu lặp lại rất đẹp, chắc chắn không thể trùng hợp được. Tôi có nghĩa là chúng ta nhớ rằng 7 là 0b111
và chúng ta biết rằng khi chúng ta chia cho 99 chúng ta có khuynh hướng lặp lại các mẫu trong cơ sở 10. Vì vậy, chúng ta sẽ có được một mẫu lặp lại trong cơ sở 8 khi chúng ta chia cho 7.
Vậy số điện thoại của chúng tôi xuất hiện ở đâu?
(int32_t)-1840700269
cũng giống như (uint_32t)2454267027
* 7 = 17179869189
Và cuối cùng là 17179869184 2^34
Có nghĩa là 17179869189 là nhiều gần gũi nhất của 7 2^34. Hoặc đặt nó theo cách khác 2454267027 là số lớn nhất sẽ phù hợp với một số uint32_t
khi nhân với 7 là rất gần với một sức mạnh của 2
Số này là gì trong bát phân?
0222222222223
Tại sao điều này quan trọng? Vâng, chúng tôi muốn chia cho 7. Con số này là 2^34/7 ... xấp xỉ. Vì vậy, nếu chúng ta nhân với nó, và sau đó leftshift 34 lần, chúng ta sẽ nhận được một số rất gần với con số chính xác.
Hai dòng cuối cùng trông giống như chúng được thiết kế để vá lỗi xấp xỉ.
Có lẽ ai đó có kiến thức và/hoặc kiến thức chuyên môn hơn trong lĩnh vực này có thể kêu gọi về điều này.
>>> magic = 2454267027
>>> def div7(a):
... if (int(magic * a >> 34) != a // 7):
... return 0
... return 1
...
>>> for a in xrange(2**31, 2**32):
... if (not div7(a)):
... print "%s fails" % a
...
thất bại bắt đầu vào 3435973841 là, hoạt kê đủ 0b11001100110011001100110011010001
Phân loại tại sao xấp xỉ thất bại là một chút ngoài tôi, và tại sao các bản vá lỗi sửa chữa nó lên là là tốt.Có ai biết làm thế nào ma thuật hoạt động vượt ra ngoài những gì tôi đã đặt xuống đây?
http://www.hackersdelight.org/divcMore.pdf –
pdf đó rất hữu ích trong việc xác định dòng cuối cùng là gì (ký hiệu sửa); tuy nhiên, nó dường như không thảo luận cụ thể thuật toán này, trừ khi tôi bỏ qua nó. – OmnipotentEntity
Các tham chiếu chính xác là [ở đây] (http://gmplib.org/~tege/divcnst-pldi94.pdf) (được thực hiện trong trình biên dịch gcc) và theo dõi [ở đây] (http://gmplib.org/~tege/division-paper.pdf). Các triển khai có thể được tìm thấy trong thư viện [GMP] (http://gmplib.org/). ('udiv_qrnnd_preinv' trong' gmp-impl.h') –