Как я могу сравнить производительность разделения 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.

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