Существуют ли компиляторы, которые оптимизируют операции с плавающей запятой для точности (в отличие от скорости)? - PullRequest
5 голосов
/ 14 января 2010

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

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

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

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

Должен быть изменен на

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

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

Спасибо

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

Ответы [ 3 ]

10 голосов
/ 14 января 2010

Ваша предпосылка ошибочна. 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
2 голосов
/ 14 января 2010

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

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

0 голосов
/ 14 января 2010

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

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

...