Как я могу сравнить производительность разделения log() и fp в С++?
Я использую класс на основе журнала в С++ для хранения очень малых значений с плавающей запятой (так как значения в противном случае выходят за рамки double
). Поскольку Im выполняет большое количество умножений, это имеет дополнительное преимущество преобразования умножений в суммы.
Однако в определенный момент моего алгоритма мне нужно разделить стандартное значение double
на значение integer
, а не на *=
на значение, основанное на журнале. Я перегрузил оператор *=
для моего логарифмического класса, а значение правой части сначала преобразуется в значение на основе журнала, запустив log()
и добавив его к значению слева.
Таким образом, фактически выполняемые операции представляют собой деление с плавающей запятой, log()
и суммирование с плавающей запятой.
Мой вопрос: было бы проще сначала преобразовать знаменатель в значение на основе журнала, которое заменило бы деление с плавающей запятой на вычитание с плавающей запятой, получив следующую цепочку операций: дважды log()
вычитание точки, суммирование с плавающей запятой.
В конце концов, это сводится к тому, что деление с плавающей запятой происходит быстрее или медленнее, чем log()
. Я подозреваю, что общий ответ заключается в том, что это зависит от компилятора и архитектуры, поэтому я говорю, что я использую gcc 4.2 от Apple на darwin 10.3.0. Тем не менее, я надеюсь получить ответ с общим замечанием о скорости этих двух операторов и/или о том, как сам измерить разницу, поскольку здесь может быть больше, например. выполнение конструкторов, которые преобразуют тип и т.д.
Ура!
Ответы
Ответ 1
Разделяете ли вы одно и то же целое число раз? Если это так, вы можете вместо этого умножить на 1./yourInteger
, и только разделить один раз. Это было бы быстрее, чем это было возможно.
Что касается вашего фактического вопроса, это зависит не только от компилятора и архитектуры, но также от микроархитектуры и данных.
На вашей конкретной платформе (darwin/x86) для текущего аппаратного обеспечения i5/i7: ~ 24 цикла для деления (1), ~ 35 циклов для log( )
(2). Однако, поскольку для деления используется только один слот для отправки инструкций, механизм переупорядочения аппаратных средств может выполнять другие полезные вычисления, в то время как разделение находится в полете; log( )
реализуется в программном обеспечении, напротив, и поэтому у процессора меньше возможностей поднять другие вычисления в латентность логарифма. Это означает, что на практике разделить часто будет очень быстро.
1) В Руководстве по оптимизации Intel
2) Измеряется путем вызова log( )
в замкнутом контуре и с помощью mach_absolute_time( )
для получения времени на стене.
Ответ 2
В архитектуре x86 логарифмы занимают значительно больше, чем деления: 85 циклов (пропускная способность) для FYL2X по сравнению с 40 циклами для FDIV. Я был бы удивлен, если другие архитектуры сильно отличаются друг от друга. Перейдите с делением с плавающей запятой.
Ответ 3
Основная проблема с делением заключается в том, что хотя это одна инструкция для большинства современных процессоров, она обычно имеет высокий latency
(31 цикл на PowerPC - не уверен, что находится на x86). Некоторая часть этой задержки может быть похоронена, хотя если у вас есть другие необязательные инструкции, которые могут быть выданы одновременно с делением. Таким образом, ответ будет зависеть от того, какие комбинации команд и зависимости у вас есть в цикле, который содержит ваше разделение (не говоря уже о том, какой процессор вы используете).
Сказав это, мое чувство кишки состоит в том, что деление будет быстрее, чем функция журнала на большинстве архитектур.
Ответ 4
Я уверен, что выполнение логарифмического вычисления с помощью любого алгоритма будет более дорогостоящим, чем даже разделение FP.
Конечно, единственный способ быть уверенным в том, чтобы закодировать его и измерить производительность кода. Из вашего описания кажется, что не должно быть слишком сложно реализовать обе версии и попробовать их бок о бок.