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

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

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

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

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

Переход на / fp: точный заставляет мое приложение работать более чем в два раза медленнее. Возможна либо точная настройка оптимизатора (т.е.отключить эту оптимизацию) или как-то обойти ее вручную?

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

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

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

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

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

Наличие одного div вместо двух является большой численной проблемой, ( xmm0, предварительно загружен 1.0f из ОЗУ), так как в зависимости от значений xmm1,2 (которые могут быть в разных диапазонах) вы можете потерять большую точность (компиляция без SSE выводит аналогичный код stack-x87-FPU).

Заключение функции в оболочку

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

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

"точный" вывод также преобразуется в "двойное" вперед и назад:

 divsd       xmm1,xmm2 
 cvtsd2ss    xmm1,xmm1 
 divsd       xmm1,xmm0 
 cvtpd2ps    xmm0,xmm1 
8
задан oyd11 5 August 2010 в 10:54
поделиться

5 ответов

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

    a/b; c/b 

->

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

Также избавляет вас от случайного деления на ноль

0
ответ дан 5 December 2019 в 22:15
поделиться

Добавьте

#pragma float_control( precise, on)

перед вычислениями и

#pragma float_control( precise,off)

после них. Думаю, это должно помочь.

3
ответ дан 5 December 2019 в 22:15
поделиться

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

2
ответ дан 5 December 2019 в 22:15
поделиться

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

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

0
ответ дан 5 December 2019 в 22:15
поделиться

Также есть __assume. Вы можете использовать __assume (a / b! = (A * (1 / b))). На самом деле я никогда не использовал __assume, но теоретически он существует именно для точной настройки оптимизатора.

1
ответ дан 5 December 2019 в 22:15
поделиться
Другие вопросы по тегам:

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