Параметры компилятора с плавающей точкой C ++ | Предотвращение A / B -> A * (1 / B)

StackOverflow https://stackoverflow.com/questions/3407493

Вопрос

Я пишу числовое программное обеспечение в Realtime, в C ++, в настоящее время составляющим его с Visual-C ++ 2008. Теперь используя «быструю» модель с плавающей точкой (/fp:fast), Различные оптимизации, большинство из них полезны мое дело, но конкретно:

a/b -> a*(1/b) Division by multiplicative inverse

слишком численно нестабилен для многих расчетов.

(видеть: Microsoft Visual C ++ оптимизация с плавающей запятой)

Переключение /fp:precise Заставляет мое приложение работать более чем в два раза ниже. Можно ли либо точно настроить оптимизатор (т. Е. Отключить эту специфическую оптимизацию), либо как-то вручную обходить его?

- Фактический пример минимального кода: -

void test(float a, float b, float c,
    float &ret0, float &ret1) {
  ret0 = b/a;
  ret1 = c/a;
} 

мой фактический код - это в основном алгоритмы, связанные с матрицей

Выход: VC (CL, версия 15, 0x86):

divss       xmm0,xmm1 
mulss       xmm2,xmm0 
mulss       xmm1,xmm0 

Наличие One Div, вместо двух, численно является большой проблемой, (XMM0, предварительно загружен с 1,0f из оперативной памяти), как в зависимости от значений XMM1,2 (что может быть в разных диапазонах), вы можете потерять много точности ( Компиляция без SSE, выводит аналогичный код стека-X87-FPU).

Упаковка функции с

#pragma float_control( precise, on, push )
...
#pragma float_control(pop)

Решает проблему точности, но во-первых, она доступна только на уровне функциональности (глобально-охвата), а во-вторых, он предотвращает встроенную функцию, (т. Е. Наказание на скорости слишком высоки)

«Точный» вывод отличается на «двойной» взад и вперед, а также хорошо:

 divsd       xmm1,xmm2 
 cvtsd2ss    xmm1,xmm1 
 divsd       xmm1,xmm0 
 cvtpd2ps    xmm0,xmm1 
Это было полезно?

Решение 5

(Странное) решение, которое я нашел: всякий раз, когда разделяться на то же значение в функции - добавьте несколько эпсилона:

    a/b; c/b 

->

    a/(b+esp1); c/(b+esp2)

Также спасает вас от случайного div на ноль

Другие советы

Добавить

#pragma float_control( precise, on)

до вычисления и

#pragma float_control( precise,off)

после этого. Я думаю, что это должно сделать это.

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

Есть также __assume. Вы можете использовать __ansume (A / B! = (A * (1 / b))). Я никогда не использовал __ansume, но в теории он существует точно, чтобы точно настроить оптимизатор.

Можете ли вы поставить функции, содержащие эти расчеты в отдельном файле исходного кода и компилируйте только этот файл с различными настройками?

Я не знаю, если это безопасно, если вам нужно будет проверить!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top