Отправьте мой ответ в:
Является ли это выражение правильным в препроцессоре C
Я немного из моей сильной стороны, и я пытаюсь понять, как работает эта конкретная оптимизация.
Как упоминалось в ответе, gcc оптимизирует целочисленное деление на 7 до:
mov edx, -1840700269
mov eax, edi
imul edx
lea eax, [rdx+rdi]
sar eax, 2
sar edi, 31
sub eax, edi
Что переводит на C как:
int32_t divideBySeven(int32_t num) {
int32_t temp = ((int64_t)num * -015555555555) >> 32;
temp = (temp + num) >> 2;
return (temp - (num >> 31));
}
Посмотрим на первую часть:
int32_t temp = ((int64_t)num * -015555555555) >> 32;
Почему это число?
Ну, возьмите 2 ^ 64 и разделите его на 7 и посмотрите, что выскочит.
2^64 / 7 = 2635249153387078802.28571428571428571429
Это похоже на беспорядок, что, если мы преобразуем его в восьмеричный?
0222222222222222222222.22222222222222222222222
Это очень симпатичный повторяющийся образец, безусловно, не может быть совпадением. Я имею в виду, что 7 - это 0b111
, и мы знаем, что когда мы делим на 99, мы стремимся получить повторяющиеся шаблоны в базе 10. Таким образом, имеет смысл, что мы получим повторяющийся шаблон в базе 8, когда мы разделим на 7.
Итак, где наш номер входит?
(int32_t)-1840700269
совпадает с (uint_32t)2454267027
* 7 = 17179869189
И наконец, 17179869184 2^34
Это означает, что 17179869189 является самым близким кратным 7 2 ^ 34. Или, говоря иначе, 2454267027 - это самое большое число, которое поместится в uint32_t
, которое при умножении на 7 очень близко к мощности 2
Что это число в восьмеричном?
0222222222223
Почему это важно? Ну, мы хотим разделить на 7. Это число составляет 2 ^ 34/7... приблизительно. Поэтому, если мы умножим на него, а затем сдвинем влево 34 раза, мы должны получить число, очень близкое к точному числу.
Последние две строки выглядят так, как будто они предназначены для исправления ошибок аппроксимации.
Возможно, кто-то, у кого есть немного больше знаний и/или опыта в этой области, может прослушивать это.
>>> 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
...
Неудачи начинаются с 3435973841, что довольно забавно 0b11001100110011001100110011010001
Классификация того, почему аппроксимация терпит неудачу, немного выше меня, и почему исправления исправлены. Кто-нибудь знает, как волшебство работает дальше того, что я здесь подавил?