【问题标题】:Integer rounding in C++C ++中的整数舍入
【发布时间】:2014-01-22 00:19:22
【问题描述】:

我试图在 c++ 中使用下面的公式。我将两个变量都声明为整数,我希望它们四舍五入,但它们似乎正在四舍五入。我已经查看了这个,但似乎无法找到问题所在。任何帮助将不胜感激。

int user_degrees_latitude, user_degrees_longitude;
const int lat_const=(-90)
const int long_const=(-180)

sector_latitude = (user_degrees_latitude - lat_const) / (10);
sector_longitude = (user_degrees_longitude - long_const) / (10);

sector_latitude 的答案应该是 13,sector_longitude 的答案应该是 11,但计算机会分别向下取整到 12 和 10。

【问题讨论】:

  • C++ 中的整数自动“向下舍入”:12.9 -> 12,如果你想要真正的舍入,有一个 round() 函数采用 double
  • 整数被截断;他们不圆
  • 您正在使用未分配的变量,这是未定义的行为。感谢您的编译器没有擦除您的磁盘。
  • 负数的四舍五入曾经取决于机器。有人告诉我,较新的 C++ 标准改变了这一点。

标签: c++ int cmath


【解决方案1】:

在 C++ 中,整数不四舍五入。相反,整数除法会截断(阅读:总是向零舍入)除法的余数。

如果你想获得整数的舍入效果,你可以这样写:

sector_latitude = static_cast<int>(((user_degrees_latitude - lat_const) / (10.0)) + 0.5);

加上 0.5 会导致截断产生舍入效果。注意在10.0 上添加.0 以在加法之前强制进行浮点除法。

我还假设 sector_latitude 是一个带有强制转换的 int。

【讨论】:

  • 非常正确。我试图给截断一个简单的定义,我相信我过于简单化了。编辑以反映您的建议。
  • 变量已经是整数了,static_cast 做了什么?
  • 除以10.0 将结果提升为浮点数(我相信实际上是双精度数)。添加0.5 现在是浮点运算。 static_cast&lt;int&gt; 强制返回整数类型,这会截断浮点运算的结果。
  • 这实际上对于负值是不正确的。例如 (10-17)/10.0 == -0.7 应该舍入为 -1,但 static_cast((10-17)/10.0 + 0.5) == 0
  • 感谢@Malloc。我再次编辑以反映这一点。对于一般情况,我认为您在下面的答案是最好的。
【解决方案2】:

C++ 中的整数除法总是向零舍入。使用浮点除法得到“精确”结果,并使用std::round按照正常规则进行四舍五入:

sector_latitude = static_cast</*type of sector_latitude*/>( std::round( (user_degrees_latitude - lat_const) / 10.0 ));

“10.0”(double)而不是“10”(int)告诉编译器使用浮点运算。如果涉及像 double 这样的浮点值,它总是选择浮点而不是整数计算。

【讨论】:

  • std::round() 不会返回整数类型。相反,它将返回传入的相同类型(floatdoublelong double)。如果 sector_latitude 是整数类型,则应添加额外的强制转换。
  • 它根本不圆。它会截断。
  • @EJP 我知道,但我相信“向零舍入”(这是截断的作用)比“截断”一词对 OP 更有帮助。
  • @user207421:它不会截断。请记住,负整数存储为 2s 补码。截断 2s 补码给出 向下舍入,而不是向零舍入。因此,向零舍入是正确的描述,而截断是不正确的。我知道大多数人并没有考虑 int 的底层表示,但鉴于它是 2s 补码,“截断”的使用充其量是模棱两可的。
【解决方案3】:

虽然这个线程已经很老了,但我很遗憾地看到两个现有答案都转换为浮点数,然后又转换回整数。如果您想将n 除以d 并将商四舍五入到最接近的整数,所有这些都使用纯整数算术,那么您只需在除法前添加d/2

q = (n + d/2) / d

(当然,d/2 可以写成 d&gt;&gt;1,但编译器会为你这样做。)所以,如果 n 是 19,d 是 4,则确切的商将是 4.75,@ 987654329@ 将产生 4(向零截断),但上面的公式将产生 5,这是所需的结果。对于OP中给出的示例,只需将最后两行更新如下:

sector_latitude = (user_degrees_latitude - lat_const + 5) / (10);
sector_longitude = (user_degrees_longitude - long_const + 5) / (10);

编辑:有人指出(感谢@kees-jan),如果n 如果nd 有不同的符号,则此解决方案将不起作用,从而产生负商。下面是一个更完整的解决方案,仍然避免了昂贵的 int-float-int 转换:

constexpr int div_round(int n, int d)
{
    int offset = (((n < 0) == (d < 0)) ? d : -d) / 2;
    return (n + offset) / d;
}

sector_latitude = div_round(user_degrees_latitude - lat_const, 10);
sector_longitude = div_round(user_degrees_longitude - long_const, 10);

【讨论】:

  • 这不适用于 n 的负值,但是...
  • @Kees-Jan:你是对的。更准确地说,如果nd 有不同的符号,它就不起作用。事实上,我在自己的项目中遇到了这个确切的问题。我会修改我的答案。不过原理是一样的:当你可以用整数算术做所有事情时,不要转换为浮点数。
猜你喜欢
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
  • 1970-01-01
  • 2010-10-19
相关资源
最近更新 更多