Тем, кто не может воспроизвести ошибку: не раскомментируйте закомментированные строки отладки, они влияют на результат.
Это означает, что проблема связана с операторами отладки. И похоже, что есть ошибка округления, вызванная загрузкой значений в регистры во время операторов вывода, поэтому другие обнаружили, что вы можете исправить это с помощью -ffloat-store
Дальнейший вопрос:
Мне было интересно, всегда ли мне включать -ffloat-store параметр?
Чтобы быть легкомысленным, должна быть причина, по которой некоторые программисты не включают -ffloat-store, иначе такой опции не существовало бы (аналогично, должна быть причина, по которой некоторые программисты действительно включают -ffloat-store). Я бы не рекомендовал всегда включать или выключать его. Включение этого параметра предотвращает некоторые оптимизации, но отключение позволяет добиться такого поведения, которое вы получаете.
Но, как правило, существует некоторое несоответствие между двоичными числами с плавающей запятой ( как компьютер использует) и десятичные числа с плавающей запятой (которые люди знакомы), и это несоответствие может привести к поведению, аналогичному тому, что вы получаете (для ясности, поведение, которое вы получаете, не вызвано из-за этого несоответствия, но может быть аналогичное поведение). Дело в том, что, поскольку у вас уже есть некоторая неясность при работе с плавающей запятой, я не могу сказать, что -ffloat-store делает это лучше или хуже.
Вместо этого вы можете изучить другие решения проблемы, с которой вы столкнулись. пытаюсь решить (к сожалению, Кениг не указывает на настоящую статью, и я не могу найти для нее очевидного канонического места, поэтому мне придется отправить вас по адресу Google).
Если вы не округляете для вывода, я бы, вероятно, посмотрел на std::modf() (в cmath) и std::numeric_limits<double>::epsilon() (в limits). Обдумывая исходную функцию round(), я считаю, что было бы чище заменить вызов std::floor(d + .5) на вызов этой функции:
// this still has the same problems as the original rounding function
int round_up(double d)
{
// return value will be coerced to int, and truncated as expected
// you can then assign the int to a double, if desired
return d + 0.5;
}
Думаю, это предполагает следующие улучшения:
// this won't work for negative d ...
// this may still round some numbers up when they should be rounded down
int round_up(double d)
{
double floor;
d = std::modf(d, &floor);
return floor + (d + .5 + std::numeric_limits<double>::epsilon());
}
Простое примечание: std::numeric_limits<T>::epsilon() определяется как наименьшее число, добавленное к 1, что создает число, не равное 1. Обычно вам нужно использовать относительный эпсилон (т. Е. Масштабировать эпсилон так или иначе, чтобы учесть тот факт, что вы работаете с числами, отличными от 1). чем 1). Сумма d, .5 и std::numeric_limits<double>::epsilon() должна быть близка к 1, поэтому группировка этого сложения означает, что std::numeric_limits<double>::epsilon() будет примерно подходящего размера для того, что мы делаем. Во всяком случае, std::numeric_limits<double>::epsilon() будет слишком большим (когда сумма всех трех меньше единицы) и может заставить нас округлить некоторые числа в большую сторону, когда мы этого не должны.
В настоящее время вам следует подумать о std::nearbyint().
person
Max Lybbert
schedule
22.09.2011
-std=c++0xи с любыми из-O0,-O1,-O2и-O3. - person Kerrek SB   schedule 22.09.2011g++ 4.4.3в 64-битной Ubuntu 10.04. Это распечатает4.5 4.6с _3 _.._ 4_ и без него. - person NPE   schedule 22.09.2011g++ -O3 x.cpp, то же самое для-O[012]) - person Lekensteyn   schedule 22.09.2011