Можно ли накатить значительно более быструю версию мода - PullRequest
5 голосов
/ 14 апреля 2010

В приложении, которое я профилирую, я обнаружил, что в некоторых сценариях эта функция может занимать более 10% общего времени выполнения.

Компилятор MSVC ++ 2008 используется, для справки ... Я не помню, отображается ли modf на одну инструкцию или есть ли какой-нибудь способ сделать это быстрее.

см. Также здесь для аналогичного вопроса по функции sqrt

В отличие от sqrt, я не знаю, как работает modf. Есть ли операция сборки? Например, вы можете сделать:

modf(float input,int &intPart, float &floatPart)
{
 intPart= (int)input;
 floatPart= input - intPart;
}

Но я предполагаю, что это влечет за собой штрафы от приведения / преобразования и т. Д. Как работает быстрая реализация?

Ответы [ 6 ]

2 голосов
/ 14 апреля 2010

Хорошая реализация modf может быть довольно быстрой (порядка 10 циклов на текущем оборудовании). Плохая реализация может быть довольно медленной (порядка 100 циклов). Реально плохо продуманная реализация может предположительно занять 1000 циклов. Я не знаю, в каком состоянии находится реализация Microsoft, но есть несколько хороших реализаций в различных библиотеках C с открытым исходным кодом, на которые вы можете взглянуть.

Ваша предложенная реализация использует несколько ярлыков и не будет соответствовать стандарту C; в частности, он будет плохо себя вести в случае, если input слишком велико для успешного преобразования в целое число. Кроме того, в некоторых случаях знак нуля неверен, но это может вас не волновать.

Также обратите внимание, что вам будет полезно использовать библиотеку компилятора / C, которая поддерживает стандарт C99, поскольку тогда вы сможете воспользоваться функцией modff и избежать издержек на преобразование в двойную точность и обратно. Я знаю, что математическая библиотека Intel (которая поставляется с их компиляторами) имеет отличные реализации modf и modff. GCC также поддерживает варианты с одинарной точностью C99.

FWIW, я проверил предложенную вами реализацию, и (при условии отличного кода компилятора) он примерно на 50% быстрее, чем библиотека Intel modff (однако реализация Intel обеспечивает правильный результат для всех входных данных). Самая быстрая правильная реализация, которую я тестировал, всего на 15% медленнее, чем ваша реализация (но опять же, дает правильный результат для всех входных данных и даже правильно устанавливает флаги состояния с плавающей запятой для загрузки).

2 голосов
/ 14 апреля 2010

Вы получаете хорошие ответы здесь, но куда уходят остальные 90% времени?

Не смотрите на исключительное время% за процедуру .

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

Таким образом, вы вполне можете обнаружить, что иногда вам даже не нужно быть в функции modf или других функциях.

Простой способ получить эту информацию - эта техника .

Добавлено: По мере того, как вы найдете возможности оптимизации, ожидайте, что общее время выполнения уменьшится, но не ожидайте, что проценты обязательно уменьшатся. Ваш% времени в modf и / или sqrt может на самом деле увеличиваться, если вы избавляетесь от других вещей, или они могут снижаться, если вы обнаружите, что можете их запомнить (и, следовательно, вызвать их меньше), например.

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

1 голос
/ 14 апреля 2010

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

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

Если вы все еще заинтересованы в прокрутке, посмотрите википедию в формате с плавающей запятой

0 голосов
/ 14 апреля 2010

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

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

0 голосов
/ 14 апреля 2010

Я также видел случаи, когда небольшие подпрограммы при вызове из DLL (как в случае с CRT) подвергаются значительному удару из связующего кода при входе и выходе из DLL. Таким образом, в таком случае сворачивание собственного и изменение способа его компиляции (например, вставка в него) может дать вам повышение производительности, даже если сама реализация идентична. YMMV, POITROAE и т. Д.

0 голосов
/ 14 апреля 2010

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

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

...