Глядя на сборку x86, созданную компилятором, я заметил, что (беззнаковые) целые деления иногда реализуются как целочисленные умножения. Эти оптимизации, кажется, следует формеВыполнение целочисленного деления с использованием умножения
value/n => (value * ((0xFFFFFFFF/n) + 1))/0x100000000
Например, выполняя деление на 9:
12345678/9 = (12345678 * 0x1C71C71D)/0x100000000
Деление на 3 будет использовать умножение 0x55555555 + 1
, и так далее.
Используя тот факт, что инструкция mul
хранит большую часть результата в регистре edx
, конечный результат деления можно получить, используя одно умножение с магическим значением. (Хотя эта оптимизация иногда используется в сочетании с побитным сдвигом в конце.)
Мне хотелось бы получить некоторое представление о том, как это работает. Когда этот подход действителен? Почему нужно добавить к нашему «магическому числу»?
Постоянная, которую вы умножаете на, является приближением обратной. Случайные +/- 1 здесь и там должны убедиться, что он всегда «закруглен» правильно. Доказательство правильности конкретного метода может быть сделано либо математически, либо методом грубой силы всех числителей. (Для 32-битных, это вполне возможно.) – Mysticial
@Mysticial: Это похоже на ответ. –
@ScottHunter Возможно, позже, когда я уйду от работы. У меня нет достаточно инструментов, чтобы дать исчерпывающий ответ. – Mysticial