Умножение обратного лучше или хуже? - PullRequest
11 голосов
/ 17 марта 2009

При работе с double типы данных умножаются на обратное лучше или хуже?

Каким образом быстрее ? Какой способ использует меньше памяти? Какой способ предпочтительнее?

Как MSIL справляется с этим?

SquareInches = MMSquared / 645.16 
SquareInches = MMSquared * 0.0015500031000062000124000248000496

Примечание: 10K пользователи заметят, что это дубликат этого вопроса , который был удален, потому что оригинал задающий вопрос решил ругать все в разделе «комментарии» вопрос.

Этот вопрос был повторно размещен, потому что это «хороший» вопрос.

Пожалуйста, снимите флажок вики-сообщества для вашего ответа, так как я только публикую его как CW, чтобы он не воспринимался как захват репутации.

Вопрос по теме:

Должен ли я использовать умножение или деление?

Ответы [ 11 ]

17 голосов
/ 17 марта 2009

Умножение на обратное происходит быстрее. Компиляторы не оптимизируют это автоматически, потому что это может привести к небольшой потере точности. (На самом деле это произошло в группе новостей D, в которой часто бывали Уолтер Брайт, и он дал понять, что компиляторы не делают этого автоматически.) Обычно вы должны делиться, потому что это более читабельно и точно.

Если вы выполняете фрагмент кода с плавающей запятой миллиард раз в цикле и , вас не волнует небольшая потеря точности и , вы будете делиться на одно и то же число несколько раз, тогда умножение на обратное может быть хорошей оптимизацией. На самом деле я получил значительное ускорение в реальном мире в нескольких случаях, подобных описанным путем умножения на обратное, но это крайние крайние случаи в циклах, выполняемых несколько миллиардов раз, которые почти ничего не делают, но умножают числа с плавающей запятой.

11 голосов
/ 17 марта 2009

Преимущество будет очень маленьким или нулевым, в зависимости от компилятора и аппаратного обеспечения.

Но это все равно может иметь значение (в узком цикле), и тогда для удобства чтения вы должны написать

SquareInches = MMSquared * (1 / 645.16)

И желательно использовать константу для 645.16.

11 голосов
/ 17 марта 2009

Какой из них " быстрее " действительно является проблемой, специфичной для процессора, или, по крайней мере, насколько быстрее зависит процессор, да, деление обычно рассматривается медленнее, чем умножение. И, конечно же, на все вопросы о производительности можно ответить «это зависит».

ОДНАКО, если бы вы спросили, что " лучше ", а не что быстрее, был бы четкий ответ, тем более читабельный лучше. Повышение производительности, на которое вы смотрите, вероятно, порядка нескольких тактов, поэтому, если вы не говорите об этом миллионы раз, вы пытаетесь сэкономить микросекунды. И не существует микросекундной оптимизации, от которой стоит жертвовать удобочитаемостью и ремонтопригодностью .

5 голосов
/ 17 марта 2009

Ответ будет зависеть от архитектуры исполняющей среды. В общем случае деление обычно несколько дороже, чем умножение на большинстве процессоров.

Так что , если только это не является проблемой производительности, я бы не стал беспокоиться об этом. Выберите коэффициент преобразования, который более понятен.

4 голосов
/ 17 марта 2009

из моего таймера кода VB

Dim SquareInches As Double
Dim MMSquared As Double = 81
Const d As Double = 645.16
Const m As Double = 1 / 645.16
Private Function TestCase1() As Boolean 'One
    'Test One Code Here
    SquareInches = MMSquared / d
    'end test code
    Return True
End Function
Private Function TestCase2() As Boolean 'Two
    'Test Two Code Here
    SquareInches = MMSquared * m
    'end test code
    Return True
End Function

Результаты

     3/17/2009 2:13:27 PM   CPU - 1.794GHz
 One - Using Division
 Two - Using Multiplication
 Outer Loops(OL)=7  Inner Loops=262,144
  ( times in ticks.  1 ms. = 10,000 ticks )
 >> Two faster, 0.0488 ticks/loop
  Ticks / Loop
 0.0342         0.0819          0.0331          0.0488
 OL Base        One             Two              One - Two
 1   8,936          21,459          8,609           12,850
 2   9,008          21,416          8,682           12,734
 3   8,965          21,423          8,643           12,780
 4   8,964          21,457          8,659           12,798
 5   8,966          21,469          8,640           12,829
 6   8,987          21,660          8,688           12,972
 7   8,963          21,429          8,802           12,627

  Average
 8,969          21,473          8,674           12,799
  Variance
 431.4          6,160.3         3,315.9       
  Standard Deviation
 20.8           78.5            57.6          
 3/17/2009 2:13:27 PM
3 голосов
/ 17 марта 2009

Алгоритмы деления в большинстве случаев медленнее , чем алгоритмы умножения.

Это компромисс, вы можете выбрать более удобочитаемый или более быстрый способ.

// Using division operation
SquareInches = MMSquared / 645.16 

Это легко читать и поддерживать, но работает медленнее, чем его мультипликативный аналог:

// Using a multiplication 
SquareInches = MMSquared * 0.0015500031000062000124000248000496

Если вы пойдете этим путем, вам потребуется больше места в памяти для хранения обратных числовых цифр, но алгоритм работает материально быстрее. Пользователь протестировал его в проекте VS2005 и сообщил о 8-кратном увеличении производительности мультипликативной версии.

Причина в том, что умножение можно слепо преобразовать в операции сдвига и сложения на процессоре, которые являются наиболее оптимизированными операциями на процессоре. Хорошим алгоритмом умножения со знаком является алгоритм Бута (процессор сделает это за вас). С другой стороны, при выполнении алгоритма деления требуются дополнительные затраты на управление, что замедляет выполнение алгоритмов деления.

Если вам нужна производительность, используйте сложения, вычитания (не более, чем сложение дополнения к двум), умножения, сдвиги, но не деления. Вы получите существенное существенное улучшение, если вы заранее вычислите все свои инверсии и будете использовать их для умножения в интенсивной программе деления.

1 голос
/ 17 марта 2009

Относительно компиляторов, выполняющих оптимизацию для mult, они могут оптимизировать это (GCC делает): SquareInches = MMSquared * (1 / 645,16).

0 голосов
/ 17 марта 2009

Я думаю, что первый метод явно предпочтительнее, потому что он явный. Представьте, что вы нашли это в чужом коде. Как вы уверены, что 0,00155 ... действительно 1 / 645,16? Что, если оригинальный программист допустил ошибку? Кроме того, как я узнаю, что 645.16 является правильным коэффициентом пересчета? Для простоты всегда лучше не оставлять числа компактными или представленными в униформе. Самый простой пример выглядит следующим образом:

//hours per day * days per year
int hoursPerYear = 24*365;

Мы можем ясно видеть, что это число верно, но как вы узнаете, неявно, что 8760 является правильным ответом? Если вам необходимо выполнить многие из этих операций, вы можете предварительно обработать данные до правильной формы ПЕРЕД вводом интенсивных вычислений. Таким образом, вам не понадобится невероятная эффективность, и вопрос станет спорным.

0 голосов
/ 17 марта 2009

В большинстве процессоров умножение быстрее, чем деление. Но это действительно несущественно для большинства приложений, по моему мнению, вам будет лучше с тем, что будет более читабельным, если только профилирование не покажет, что это критический путь.

Если это интерпретируемый язык, количество времени на чтение источника и преобразование его в числа сократит время, затрачиваемое на выполнение математических операций, особенно если вы используете столько значащих цифр для умножения. (Вы уверены, что вам действительно нужно столько значащих цифр?)

0 голосов
/ 17 марта 2009

Умножение и сложение - самые быстрые операции, которые поддерживает процессор. Некоторые процессоры даже не имеют аппаратной реализации таких вещей, как деление, квадратный корень и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...