简体   繁体   English

尝试使用std :: round()时,我应该添加少量吗?

[英]Should I add a tiny amount when trying to use std::round()?

Here is a situation where a round_to_2_digits() function is rounding down when we expected it to round up. 在这种情况下,当我们期望四舍五入时, round_to_2_digits()函数会四舍五入。 This turned out to be the case where a number cannot be represented exactly in a double. 事实证明,数字不能精确地以双精度表示。 I don't remember the exact value, but say this: 我不记得确切的值,而是这样说:

double value = 1.155;
double value_rounded = round_to_2_digits( value );

The value was the output of a function, and instead of being exactly 1.155 like the code above, it actually was returning something like 1.15499999999999999. value是函数的输出,而不是像上面的代码那样精确地为1.155,它实际上返回的是类似1.15499999999999999的值。 So calling std::round() on it would result in 1.15 instead of 1.16 like we thought. 因此,在其上调用std::round()将导致1.15而不是我们认为的1.16。

Questions: 问题:

I'm thinking it may be wise to add a tiny value in round_to_2_digits() prior to calling std::round() . 我认为在调用std::round()之前在round_to_2_digits()添加一个很小的值可能是明智的。

  • Is this standard practice, or acceptable? 这是标准做法,还是可以接受的? For example, adding the 0.0005 to the value being rounded. 例如,对要取整的值加上0.0005。
  • Is there a mathematical term for this kind of "fudge factor"? 这种“软糖因子”是否有数学术语?
    • EDIT: "epsilon" was the term I was looking for. 编辑: “ epsilon”是我正在寻找的术语。
  • And since the function rounds to only 2 digits after the decimal point, should I be adding 0.001? 并且由于函数舍入到小数点后仅两位数,我应该加0.001吗? 0.005? 0.005? 0.0005? 0.0005?

The rounding function is quite simple: 舍入函数非常简单:

double round_to_2_decimals( double value )
{
    value *= 100.0;
    value = std::round(value);
    value /= 100.0;
    return value;
}

Step one is admitting that double may not be the right data type for your application. 第一步是承认double可能不是您应用程序的正确数据类型。 :-) Consider using a fixed-point type, or multiplying all of your values by 100 (or 1000, or whatever), and working with integer values. :-)考虑使用定点类型,或将所有值乘以100(或1000,或其他任何值),然后使用整数值。

You can't actually guarantee that adding any particular small epsilon won't give you the wrong results in some other situation. 您实际上不能保证在任何其他情况下添加任何特定的小epsilon不会给您错误的结果。 What if your value actually was 1.54999999..., and you rounded it up? 如果您的值实际上 1.54999999 ...,然后将其取整怎么办? Then you'd have the wrong value the other way. 否则,您将获得错误的价值。

The problem with your suggested solution is that at the end of it, you're still going to have a binary fraction that's not necessarily equal to the decimal value you're trying to represent. 建议的解决方案的问题在于,在解决方案的最后,您仍然会有一个二进制分数,该分数不一定等于您要表示的十进制值。 The only way to fix this is to use a representation that can exactly represent the values you want to use. 解决此问题的唯一方法是使用可以精确表示您要使用的值的表示形式。

This question doesn't make a lot of sense. 这个问题没有多大意义。 POSIX mandates std::round rounds half away from zero. POSIX要求std::round从零开始std::round一半。 So the result should in fact be 116 not 115 . 因此,结果实际上应该是116而不是115 In order to actually replicate your behavior, I had to use a function that pays attention to rounding mode: 为了实际复制您的行为,我必须使用一个关注舍入模式的函数:

std::fesetround(FE_DOWNWARD);
std::cout << std::setprecision(20) << std::rint(1.155 * 100.0);

This was tested on GCC 5.2.0 and Clang 3.7.0. 这已在GCC 5.2.0和Clang 3.7.0上进行了测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM