Почему много (старых) программ используют слово (0.5 + input) вместо round (input)?

Различия находятся в возвращаемом значении, дающем входные данные вокруг tie-break, которые я считаю, например этот код:

int main()
{
    std::cout.precision(100);

    double input = std::nextafter(0.05, 0.0) / 0.1;
    double x1 = floor(0.5 + input);
    double x2 = round(input);

    std::cout << x1 << std::endl;
    std::cout << x2 << std::endl;
}

который выводит:

1
0

Но в конце концов, это просто разные результаты, один выбирает свой предпочтительный. Я вижу множество "старых" программ на C/С++, используя floor(0.5 + input) вместо round(input).

Есть ли историческая причина? Самый дешевый на процессоре?

Ответ 1

std::round введен в С++ 11. До этого было доступно только std::floor, поэтому программисты использовали его.

Ответ 2

Нет никакой исторической причины. Такое отвращение существует с года. Народ делает это, когда они чувствуют себя очень, очень непослушными. Это серьезное злоупотребление арифметикой с плавающей запятой, и многие опытные профессиональные программисты падают за нее. Даже Java-устройства делали до версии 1.7. Смешные ребята.

Моя гипотеза заключается в том, что достойная функциональная функция округления немецкого округления официально не была доступна до С++ 11 (несмотря на то, что C получила их на C99), но это действительно не оправдание для принятия так называемой альтернативной.

Здесь вещь: floor(0.5 + input) не всегда возвращает тот же результат, что и соответствующий вызов std::round!

Причина довольно тонкая: точка отсечения для немецкого округления, a.5 для целого числа a, является случайным свойством вселенной диадическим рациональным. Поскольку это может быть представлено точно в плавающей точке IEEE754 до 52-й степени 2, а после этого округление в любом случае равно нулю, std::round всегда работает правильно. Для других схем с плавающей точкой обратитесь к документации.

Но добавление 0.5 в double может привести к неточности, вызвав небольшое недочет или превышение для некоторых значений. Если вы подумаете об этом, добавив два значения double вместе - это начало невольных преобразований денонарей - и применение функции, которая является очень сильной функцией ввода (например, функция округления), неизбежно заканчивается слезами.

Не делайте этого.

Ссылка: Почему Math.round(0.49999999999999994) возвращает 1

Ответ 3

Я думаю, что здесь вы ошибаетесь:

Но в конце они просто разные результаты, один выбирает предпочтительнее. Я вижу множество "старых" программ на C/С++, используя пол (0,5 + ввод) вместо раунда (ввод).

Это не так. Вы должны выбрать схему правильного округления для домена. В финансовом приложении вы будете использовать правила банкира (не используя поплавок, кстати). Однако при выборке, округление с использованием static_cast<int>(floor(f + .5)) дает меньше шума выборки, это увеличивает динамический диапазон. Когда выравнивание пикселей, то есть преобразование положения в координаты экрана, использование любого другого метода округления даст отверстия, зазоры и другие артефакты.

Ответ 4

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

С floor() вы можете соответствовать результатам. Если поплавок равен .5 или больше, добавление его будет увеличиваться до следующего значения int. Но .49999 просто отбросит десятичное число.

Ответ 5

Многие программисты адаптируют идиомы, которые они изучали при программировании на других языках. Не все языки имеют функцию round(), и в этих языках нормально использовать floor(x + 0.5) в качестве замены. Когда эти программисты начинают использовать С++, они не всегда понимают, что есть встроенный round(), они продолжают использовать стиль, к которому они привыкли.

Другими словами, только потому, что вы видите много кода, который что-то делает, это не значит, что для этого есть веская причина. Вы можете найти примеры этого на каждом языке программирования. Помните Закон о осетроводе:

Девяносто процентов всего дерьмо