Существуют ли компиляторы, которые оптимизируют операции с плавающей запятой для обеспечения точности (а не скорости)?

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

Вопрос

Мы знаем, что компиляторы все лучше и лучше оптимизируют наш код и ускоряют его работу, но у меня вопрос: существуют ли компиляторы, которые могут оптимизировать операции с плавающей запятой для обеспечения большей точности.

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

Итак, операция с плавающей запятой, например

y = x*(a + b); // faster but less accurate

Следует изменить на

y = x*a + x*b; // slower but more accurate

Существуют ли какие-либо компиляторы, которые будут оптимизироваться для повышения точности с плавающей запятой за счет скорости, как я показал выше?Или главная проблема скорости компиляторов заключается в том, чтобы не учитывать точность операций с плавающей запятой?

Спасибо

Обновлять:Выбранный ответ показал очень хороший пример, когда этот тип оптимизации не будет работать, поэтому компилятор не сможет заранее узнать, какой способ оценки y является более точным.Спасибо за встречный пример.

Это было полезно?

Решение

Ваша предпосылка ошибочна. x*(a + b), является (в целом) не менее точным, чем x*a + x*b.Фактически, он часто будет более точным, поскольку выполняет только две операции с плавающей запятой (и, следовательно, допускает только две ошибки округления), тогда как последний выполняет три операции.

Если вы знаете что-то об ожидаемом распределении значений для x, a, и b априори, то вы могли бы принять обоснованное решение, но составители почти никогда не имеют доступа к такого рода информации.

Кроме того, что, если человек, пишущий программу, на самом деле имел в виду x*(a+b) и конкретно в розыске какие именно округления вызваны этой конкретной последовательностью операций?Подобные вещи на самом деле довольно распространены в высококачественных числовых алгоритмах.

Лучше делать то, что написал программист, а не то, что, по вашему мнению, он имел в виду.

Редактировать -- Пример, иллюстрирующий случай, когда предложенное вами преобразование приводит к катастрофической потере точности:предполагать

x = 3.1415926535897931
a = 1.0e15
b = -(1.0e15 - 1.0)

Затем, оценивая в double мы получаем:

x*(a + b) = 3.1415926535897931

но

x*a + x*b = 3.0

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

Компиляторы обычно «оптимизируют» точность, а не скорость, точность определяется как точная реализация стандарта IEEE 754.В то время как целочисленные операции можно переупорядочивать любым способом, не вызывающим переполнения, операции FP должны выполняться точно так, как указывает программист.Это может принести в жертву числовую точность (обычные компиляторы C не способны оптимизировать это), но точно реализует то, что просил программист.

Программист, который уверен, что он не оптимизировал точность вручную, может включить такие функции компилятора, как GCC. -funsafe-math-optimizations и -ffinite-math-only чтобы, возможно, получить дополнительную скорость.Но обычно особой выгоды не бывает.

Нет, нет.Стивен Кэнон приводит несколько веских причин, почему это глупая идея, и он прав;поэтому вы не найдете компилятора, который это делает.

Если вы, как программист, обладаете некоторыми знаниями о диапазонах чисел, которыми вы манипулируете, вы можете использовать круглые скобки, временные переменные и подобные конструкции, чтобы четко подсказать компилятору, как вы хотите, чтобы все было сделано.

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