После поиска долгого времени для ошибки производительности я читал о нестандартных значениях с плавающей точкой.
По-видимому, денормализованные значения с плавающей точкой могут быть главной проблемой производительности, как проиллюстрирован в этом вопросе: Почему делает изменение 0.1f к 0, замедляют производительность 10x?
У меня есть Intel Core 2 Duo, и я компилирую с gcc, с помощью -O2
.
Таким образом, что я делаю? Я могу так или иначе дать g команду ++ избегать нестандартных значений? В противном случае могу я так или иначе тестировать если a float
нестандартно?
Вы можете проверить, является ли число с плавающей запятой денормальным, используя
#include <cmath>
if ( std::fpclassify( flt ) == FP_SUBNORMAL )
(Предостережение: я не уверен, что это будет выполняться на полной скорости на практике.)
В C + +03, и этот код работал у меня на практике,
#include <cmath>
#include <limits>
if ( flt != 0 && std::fabsf( flt ) < std::numeric_limits<float>::min() ) {
// it's denormalized
}
Чтобы решить, где его применить, вы можете использовать анализатор на основе выборки, такой как Shark, VTune или Zoom , чтобы выделить замедленные инструкции денормальными значениями. Микрооптимизация, даже в большей степени, чем другие оптимизации, совершенно безнадежна без анализа как до, так и после.
Большинство математических сопроцессоров имеют возможность усекать денормальные значения до нуля. На x86 это флаг FZ (Сброс до нуля) в регистре управления MXCSR. Проверьте свою реализацию CRT на наличие функции поддержки для установки регистра управления. Он должен быть в
, что-то вроде _controlfp (). Бит опции обычно имеет "FLUSH" в определенном символе #.
Еще раз проверьте свои математические результаты после того, как вы установите это. Что вы должны делать в любом случае, получение денормальных состояний - признак проблем со здоровьем.
Очевидно, вам нужны некоторые инструкции ЦП, называемые FTZ (Сброс до нуля) и DAZ (Денормальные значения равны нулю).
Я нашел информацию на аудио-сайте, но их ссылка на документацию Intel отсутствовала. Очевидно, это инструкции SSE2, поэтому они должны работать на процессорах AMD, которые это поддерживают.
Я не знаю, что вы можете сделать в GCC, чтобы сделать это портативным. Однако вы всегда можете написать встроенный ассемблерный код, чтобы использовать их. Возможно, вам придется заставить GCC использовать только SSE2 для вычислений с плавающей запятой.
Как дополнение к другим ответам, если у вас действительно есть проблема с денормальными значениями с плавающей запятой, у вас, вероятно, есть проблема с точностью в дополнение к проблеме с производительностью.
Было бы неплохо проверить, можете ли вы реструктурировать свои вычисления, чтобы оставить числа больше, чтобы избежать потери точности и производительности.
Подождите. Прежде чем что-либо делать, знаете ли вы, что ваш код сталкивается с ненормальными значениями и что они оказывают измеримое влияние на производительность?
Предполагая, что вы это знаете, знаете ли вы, что алгоритм (ы), который вы используете стабильно, если денормальная поддержка отключена? Получение неправильного ответа в 10 раз быстрее обычно не является хорошей оптимизацией производительности.
Помимо этих проблем:
Если вы хотите обнаружить ненормальные значения, чтобы подтвердить их присутствие, у вас есть несколько вариантов. Если у вас есть стандартная библиотека C99 или Boost, вы можете использовать макрос fpclassify
. В качестве альтернативы вы можете сравнить абсолютные значения ваших данных с наименьшим положительным нормальным числом.
Вы можете настроить оборудование для сброса денормальных значений в ноль (FTZ) или обработки денормальных входных значений как нуля (DAZ). Самый простой способ, если он правильно поддерживается на вашей платформе, - это, вероятно, использовать функцию fesetenv ()
в заголовке C fenv.h
. Тем не менее, это одна из наименее широко поддерживаемых функций стандарта C, и в любом случае она зависит от платформы. Вы можете просто использовать некоторую встроенную сборку, чтобы напрямую установить состояние FPU в (DAZ / FTZ).