У меня есть высокоточный ODE (обыкновенные дифференциальные уравнения) решатель, написанный на C ++. Я делаю все вычисления с пользовательским типом real_type
, Существует typedef, объявляющий этот тип в заголовке:
typedef long double real_type;
Я решил изменить длинный двойной тип на __float128
для большей точности. В дополнение к этому я включил quadmath.h
и заменил все стандартные математические функции на те из libquadmath.
Если «длинная двойная» версия создается без каких-либо флагов оптимизации, некоторый эталонный ODE решается за 77 секунд. Если эта версия построена с флагом -O3, то же ODE решается за 25 секунд. Таким образом, флаг -O3 ускоряет вычисления в три раза.
Но в версии «__float 128», собранной без флагов, аналогичный ODE решается за 190 секунд, а с -O3 — за 160 секунд (разница ~ 15%). Почему оптимизация -O3 дает такой слабый эффект для вычислений с четверной точностью? Может быть, я должен использовать другие флаги компилятора или включить другие библиотеки?
Оптимизация компилятора работает следующим образом: компилятор распознает определенные шаблоны в вашем коде и заменяет их эквивалентными, но более быстрыми версиями. Не зная точно, как выглядит ваш код и какие оптимизации выполняет компилятор, мы не можем сказать, чего не хватает компилятору.
Вполне вероятно, что несколько оптимизаций, которые компилятор знает, как выполнить для собственных типов с плавающей запятой и их операций, он не знает, чтобы выполнить на __float128 и реализации библиотек операций. Он может не распознавать эти операции такими, какие они есть. Может быть, он не может смотреть на реализации библиотеки (вы должны попробовать скомпилировать библиотеку вместе с вашей программой и включить оптимизацию во время соединения).
Та же оптимизация обеспечила практически одинаковую выгоду. Процент снизился только потому, что сама математика заняла больше времени.
Чтобы полагать, что оптимизация должна составлять один и тот же процент, вы должны полагать, что если математика займет больше времени, оптимизатор найдет больше сбережений. Почему ты так думаешь?
Если ваша цель — архитектура x86, то в GCC __float128
является фактическим типом FP четверной точности, в то время как long double
это 96-битный тип FP x87 (расширенный дважды).
Разумно, что математика с типами меньшей точности может быть быстрее, чем математика с типами большей точности. Также разумно, что математика с нативными типами оборудования может быть быстрее, чем математика с неродными типами.