Уловки C / C ++ для обеспечения порядка операций с плавающей запятой - PullRequest
3 голосов
/ 19 сентября 2019

Я ищу способы заставить gcc соблюдать определенный порядок операций (это не обязательно должен быть порядок, который минимизирует ошибку с плавающей запятой, просто порядок, в котором я бы хотел) относительно арифметики двойной точности конкретного разделакода, допуская полный -O3 -funsafe-math-optimizations в другом месте.Я видел несколько постов по этому вопросу:

Являются ли операции с плавающей запятой в C ассоциативными?

https://devblogs.microsoft.com/cppblog/do-you-prefer-fast-or-precise/

C /Математический порядок операций C ++

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

Например, рассмотрим

#include <iostream>
#include <string>
#include <iomanip>

using std::cout;

int main()
{
    double a = 1.0 + 1.3e-16;
    double b = 1.0;
    double c = 100.0;

    double d = (a - b) / c;
    double e = a / c - b / c;

    cout << std::scientific;
    cout << "Calculation d = " << d << "\n";
    cout << "Calculation e = " << e << "\n";

    double f = 1.0;
    double g = 2e-15;
    double h = 1.0;
    double i = 1e-15;

    double j = (f + g) - (h + i);
    double k = (f - h) + (g - i);
    double m = f + g - h - i;
    double n = f - h + g - i;

    cout << "Calculation j = " << j << "\n";
    cout << "Calculation k = " << k << "\n";
    cout << "Calculation m = " << m << "\n";
    cout << "Calculation n = " << n << "\n";
}

Использование http://cpp.sh, Я получаю

Calculation d = 2.220446e-18
Calculation e = 1.734723e-18
Calculation j = 8.881784e-16
Calculation k = 1.000000e-15
Calculation m = 9.984014e-16
Calculation n = 1.000000e-15

Это не зависело от уровня оптимизации, который я использовал, поэтому кажется, что компилятор будет вычислять вещи в порядке, который я ожидаю, основываясь на выражении, плюс даже поддерживает порядок слева направо для+/- Но абсолютно ли это гарантировано, когда оптимизация включена?

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...