Я пишу числовое программное обеспечение в реальном времени на 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;
}
[myфактический код в основном связан с матричными алгоритмами]
Вывод: 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)
Решает проблему точности, но, во-первых, она доступна только на уровне функций (global-scope), а во-вторых, она предотвращает встраиваниефункция (т. е. слишком высокие штрафы за скорость)
«точный» вывод приводится также к «удвоению» вперед и назад:
divsd xmm1,xmm2
cvtsd2ss xmm1,xmm1
divsd xmm1,xmm0
cvtpd2ps xmm0,xmm1