Могу ли я гарантировать, что компилятор C++ не изменит порядок моих вычислений?
в настоящее время я читаю отличные библиотека для Double-Double и Quad-Double арифметики бумага, и в первых нескольких строках я замечаю, что они выполняют сумму следующим образом:
std::pair<double, double> TwoSum(double a, double b)
{
double s = a + b;
double v = s - a;
double e = (a - (s - v)) + (b - v);
return std::make_pair(s, e);
}
вычисление ошибки,e
, полагается на то, что расчет следует этому порядку операций именно из-за неассоциативных свойств математики с плавающей запятой IEEE-754.
если я скомпилирую это в рамках современного оптимизация компилятора C++ (например, MSVC или gcc), можно ли гарантировать, что компилятор не оптимизирует способ выполнения этого вычисления?
во-вторых, гарантируется ли это в любом месте стандарта C++?
10 ответов
Да, это безопасно (по крайней мере в данном случае). Вы используете только два "оператора", основное выражение
вы можете посмотреть страницу руководства g++: http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Optimize-Options.html#Optimize-Options
особенно-fassociative-math,-ffast-math и-ffloat-store
в соответствии с руководством g++ он не будет переупорядочивать ваше выражение, Если вы специально не запросите его.
Это очень обоснованная проблема, потому что компилятор Intel C++, который очень широко используется, по умолчанию выполняет оптимизацию, которая может изменить результат.
Я был бы очень удивлен, если бы какой-либо компилятор ошибочно предположил ассоциативность арифметических операторов с параметрами оптимизации по умолчанию.
но будьте осторожны с расширенной точностью регистров FP.
обратитесь к документации компилятора о том, как убедиться, что значения FP не имеют расширенной точности.
В общем, вы должны быть в состоянии -- оптимизатор должен знать свойства реальных операций.
тем не менее, я бы проверил компилятор, который я использовал.
между оптимизацией компилятора и выполнением вне порядка на процессоре это почти гарантия того, что все не произойдет точно так, как вы их заказали.
однако также гарантируется, что это никогда не изменит результат. C++ следует стандартному порядку операций, и все оптимизации сохраняют это поведение.
Итог: Не беспокойтесь об этом. Написать код на C++, чтобы быть математически правильным и доверять компилятору. Если что-то пойдет не так, проблема была почти наверняка не в компиляторе.
Если вам действительно нужно, я думаю, вы можете сделать функцию noinline no_reorder(float x) { return x;}, а затем использовать ее вместо скобок. Очевидно, что это не особенно эффективное решение.
в соответствии с другими ответами вы должны иметь возможность полагаться на компилятор, делающий правильную вещь - большинство компиляторов позволяют компилировать и проверять ассемблер (использовать-S для gcc) - вы можете сделать это, чтобы убедиться, что вы получите порядок работы, который вы ожидаете.
различные уровни оптимизации (в gcc, -O _O2 и т. д.) позволяют перестроить код (однако такой последовательный код вряд ли будет затронут) , но я бы предложил вам изолировать эту конкретную часть код в отдельный файл, так что вы можете управлять уровнем оптимизации для расчета.
короткий ответ: компилятор, вероятно, изменит порядок ваших вычислений, но он никогда не изменит поведение вашей программы (если ваш код не использует выражение с неопределенным поведением:http://blog.regehr.org/archives/213)
однако вы все равно можете повлиять на это поведение, отключив все оптимизации компилятора (опция "-O0" с gcc). Если вам все еще нужен компилятор для оптимизации остальной части кода, Вы можете поместить эту функцию в разделение." c", который вы можете скомпилировать с помощью "- O0". Кроме того, вы можете использовать некоторые писаки. Например, если вы чередуете код с вызовами функции extern, компилятор может решить, что переупорядочивать код небезопасно, поскольку функция может иметь неизвестный побочный эффект. Вызов "printf" для печати значения ваших промежуточных результатов приведет к аналогичному поведению.
в любом случае, если у вас нет какой-либо очень веской причины (например, отладки), вы обычно не хотите заботиться об этом, и вы должны доверять компилятору.