Правило 1: профиль перед оптимизацией
Прежде чем вкладывать какие-либо усилия в убеждение, что вы можете победить оптимизатор, вы должны профилировать все и выяснить, где на самом деле находится узкое место. В общем, маловероятно, что sqrt()
само по себе является вашим узким местом.
Правило 2: замените алгоритм перед заменой стандартной функции
Даже если sqrt()
является узким местом, вполне вероятно, что существуют алгоритмические подходы (такие как сортировка расстояний по длине в квадрате, которые легко вычисляются без вызова какой-либо математической функции), которые могут устранить необходимость вызова sqrt()
на первом месте.
Что компилятор сделает для вас, если вы больше ничего не сделаете
Многие современные компиляторы C готовы встроить функции CRT на более высокие уровни оптимизации, делая естественное выражение, включая вызовы sqrt()
, настолько быстрым, насколько это необходимо.
В частности, я проверил MinGW gcc v3.4.5, и он заменил вызов sqrt()
на встроенный код, который перетасовывал состояние FPU, и в ядре использовал инструкцию FSQRT
. Благодаря тому, как стандарт C взаимодействует с плавающей точкой IEEE 754, он должен был следовать FSQRT
с некоторым кодом для проверки исключительных условий и вызова реальной функции sqrt()
из библиотеки времени выполнения, чтобы плавающая точка Исключения могут обрабатываться библиотекой в соответствии с требованиями стандарта.
При встроенном sqrt()
и использовании в контексте более крупного выражения double
результат является максимально эффективным с учетом ограничений соответствия стандартам и сохранения полной точности.
Для этой (очень распространенной) комбинации компилятора и целевой платформы и без знания варианта использования этот результат довольно хорош, а код понятен и поддерживается.
На практике любые хитрости сделают код менее понятным и, вероятно, менее обслуживаемым. В конце концов, вы бы предпочли сохранить (-b + sqrt(b*b - 4.*a*c)) / (2*a)
или непрозрачный блок встроенных сборок и таблиц?
Кроме того, на практике вы, как правило, можете рассчитывать на то, что авторы компилятора и библиотеки будут в полной мере использовать возможности вашей платформы и, как правило, больше знать о тонкостях оптимизации, чем вы.
Однако в редких случаях можно добиться большего.
Один из таких случаев - в расчетах, когда вы знаете, какая точность вам действительно нужна, а также знаете, что вы не зависите от обработки исключений с плавающей запятой в стандарте C и можете согласиться с тем, что поставляет аппаратная платформа.
Редактировать: Я немного перестроил текст, чтобы сделать акцент на профилировании и алгоритмах, как это предлагал Джонатан Леффлер в комментариях. Спасибо, Джонатан.
Edit2: Исправлена опечатка старшинства в квадратичном примере, замеченная острыми глазами kmm .