Why do lots of (old) programs use floor(0.5 + input) instead of round(input)?

旧城冷巷雨未停 提交于 2019-12-18 11:14:46

问题


The differences reside in the returned value giving inputs around tie-breaking I believe, such as this code:

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;
}

which outputs:

1
0

But they are just different results in the end, one chooses its preferred one. I see lots of "old" C/C++ programs using floor(0.5 + input) instead of round(input).

Is there any historic reason? Cheapest on the CPU?


回答1:


std::round is introduced in C++11. Before that, only std::floor was available so programmers were using it.




回答2:


There is no historic reason whatsoever. This kind of deviance has been around since year dot. Folk do this when they are feeling very, very naughty. It's a serious abuse of floating point arithmetic, and many experienced professional programmers fall for it. Even the Java bods did up to version 1.7. Funny guys.

My conjecture is that a decent out-of-the-box German rounding function was not formally available until C++11 (despite C getting theirs in C99), but that really is no excuse for adopting the so-called alternative.

Here's the thing: floor(0.5 + input) does not always recover the same result as the corresponding std::round call!

The reason is quite subtle: the cutoff point for a German rounding, a.5 for an integer a is, by a coincidental property of the universe, a dyadic rational. As this can be represented exactly in an IEEE754 floating point up to the 52nd power of 2, and thereafter rounding is a no-op anyway, std::round always works properly. For other floating point schemes, consult the documentation.

But adding 0.5 to a double can introduce imprecision causing a slight under or overshoot for some values. If you think about it, adding two double values together - that are the inception of unwitting denary conversions - and applying a function that is a very strong function of the input (such as a rounding function), is bound to end in tears.

Don't do it.

Reference: Why does Math.round(0.49999999999999994) return 1




回答3:


I think this is where you err:

But they are just different results in the end, one chooses its preferred one. I see lots of "old" C/C++ programs using floor(0.5 + input) instead of round(input).

That is not the case. You must select the right rounding scheme for the domain. In a financial application, you'll round using banker's rules (not using float by the way). When sampling, however, rounding up using static_cast<int>(floor(f + .5)) yields less sampling noise, this increments the dynamic range. When aligning pixels, i.e. converting a position to screen coordinates, using any other rounding method will yield holes, gaps, and other artifacts.




回答4:


A simple reason could be that there are different methods of rounding numbers so unless you knew the method used, you could different results.

With floor(), you can be consistent with the results. If the float is .5 or greater, adding it will bump up to the next int. But .49999 will just drop the decimal.




回答5:


Many programmers adapt idioms that they learned when programming with other languages. Not all languages have a round() function, and in those languages it's normal to use floor(x + 0.5) as a substitute. When these programmers start using C++, they don't always realize that there's a built-in round(), they continue to use the style they're used to.

In other words, just because you see lots of code that does something, it doesn't mean there's a good reason to do it. You can find examples of this in every programming language. Remember Sturgeon's Law:

ninety percent of everything is crap



来源:https://stackoverflow.com/questions/47302544/why-do-lots-of-old-programs-use-floor0-5-input-instead-of-roundinput

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!