Предотвращение нестандартных значений в C++

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

По-видимому, денормализованные значения с плавающей точкой могут быть главной проблемой производительности, как проиллюстрирован в этом вопросе: Почему делает изменение 0.1f к 0, замедляют производительность 10x?

У меня есть Intel Core 2 Duo, и я компилирую с gcc, с помощью -O2.

Таким образом, что я делаю? Я могу так или иначе дать g команду ++ избегать нестандартных значений? В противном случае могу я так или иначе тестировать если a float нестандартно?

24
задан Community 23 May 2017 в 10:30
поделиться

5 ответов

Вы можете проверить, является ли число с плавающей запятой денормальным, используя

#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 , чтобы выделить замедленные инструкции денормальными значениями. Микрооптимизация, даже в большей степени, чем другие оптимизации, совершенно безнадежна без анализа как до, так и после.

14
ответ дан 28 November 2019 в 23:15
поделиться

Большинство математических сопроцессоров имеют возможность усекать денормальные значения до нуля. На x86 это флаг FZ (Сброс до нуля) в регистре управления MXCSR. Проверьте свою реализацию CRT на наличие функции поддержки для установки регистра управления. Он должен быть в , что-то вроде _controlfp (). Бит опции обычно имеет "FLUSH" в определенном символе #.

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

7
ответ дан 28 November 2019 в 23:15
поделиться

Очевидно, вам нужны некоторые инструкции ЦП, называемые FTZ (Сброс до нуля) и DAZ (Денормальные значения равны нулю).

Я нашел информацию на аудио-сайте, но их ссылка на документацию Intel отсутствовала. Очевидно, это инструкции SSE2, поэтому они должны работать на процессорах AMD, которые это поддерживают.

Я не знаю, что вы можете сделать в GCC, чтобы сделать это портативным. Однако вы всегда можете написать встроенный ассемблерный код, чтобы использовать их. Возможно, вам придется заставить GCC использовать только SSE2 для вычислений с плавающей запятой.

0
ответ дан 28 November 2019 в 23:15
поделиться

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

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

1
ответ дан 28 November 2019 в 23:15
поделиться

Подождите. Прежде чем что-либо делать, знаете ли вы, что ваш код сталкивается с ненормальными значениями и что они оказывают измеримое влияние на производительность?

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

Помимо этих проблем:

  • Если вы хотите обнаружить ненормальные значения, чтобы подтвердить их присутствие, у вас есть несколько вариантов. Если у вас есть стандартная библиотека C99 или Boost, вы можете использовать макрос fpclassify . В качестве альтернативы вы можете сравнить абсолютные значения ваших данных с наименьшим положительным нормальным числом.

  • Вы можете настроить оборудование для сброса денормальных значений в ноль (FTZ) или обработки денормальных входных значений как нуля (DAZ). Самый простой способ, если он правильно поддерживается на вашей платформе, - это, вероятно, использовать функцию fesetenv () в заголовке C fenv.h . Тем не менее, это одна из наименее широко поддерживаемых функций стандарта C, и в любом случае она зависит от платформы. Вы можете просто использовать некоторую встроенную сборку, чтобы напрямую установить состояние FPU в (DAZ / FTZ).

23
ответ дан 28 November 2019 в 23:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: