C++:如何将double四舍五入为int?

156

我有一个名为x的double变量,应该是55,但实际上存储为54.999999999999943157,这是我刚刚意识到的。

所以当我执行以下操作时:

double x = 54.999999999999943157;
int y = (int) x;

y = 54而不是55!

这让我困惑了很长时间。我该如何使它正确地四舍五入?


1
你可以将0.5加到这个数字上,然后进行强制类型转换,使其截断为整数。你需要将负数四舍五入吗? - Blastfurnace
6
你可以使用这个预处理器定义:#define ROUND_2_INT(f)((int)(f >= 0.0?(f + 0.5):(f-0.5))) - c00000fd
3
将负数输入加上+0.5再转换成整数会得到错误的答案。正确的快速方法是测试输入符号是否为<0,然后在将负数输入转换为整数之前从中减去0.5。大多数以下答案没有很好地解释这一点。注意,高精度过程应使用新的较慢的“round()”函数。 - DragonLord
对我来说,下面的程序会打印出“55”。我做错了什么吗?`#include<iostream>using namespace std;int main() { float x = 55; int y = (int) x; cout << y; }` - plafratt
显示剩余5条评论
5个回答

173

如果 x > 0,则在转换之前添加 0.5(如果 x < 0,则减去 0.5),因为编译器总是截断。

float x = 55; // stored as 54.999999...
x = x + 0.5 - (x<0); // x is now 55.499999...
int y = (int)x; // truncated to 55

C++11引入了std::round,它很可能在底层使用类似的逻辑将0.5添加到| x |中(如果感兴趣,请查看链接),但显然更加健壮。

接下来可能会有一个问题,即为什么浮点数不能精确地存储为55。有关说明,请参见 stackoverflow 答案。


3
我不会使用“round down”这个词组,因为它可能被解释为将“-0.5”舍入为“-1”。 - user1084944
1
-1 这只是一个勉强可行的解决方案。Zik的答案更好,因为它使用了一个库函数:适用于负数,不会进行奇怪的转换,并且明确表达了其意图。 - Henry Henrinson
6
“stored as stored as 54.999999…” 是什么意思?在 IEEE 754 的二进制32位浮点数中,数字“55”可以被准确表示,其表示为0x425c0000。你可以看到,它是超过精确的:它有足够的数字来存储你添加的任何小数部分。而对于“0.5”尤其如此,因为它是2的幂。 - Ruslan
3
这不准确,可能会导致速度变慢。请参考clang-tidy的解释:http://clang.llvm.org/extra/clang-tidy/checks/misc-incorrect-roundings.html - ACyclic
2
@Pac0 更新了此链接,详细阐述了为何这是不准确的:http://releases.llvm.org/5.0.2/tools/clang/tools/extra/docs/clang-tidy/checks/misc-incorrect-roundings.html - ACyclic
显示剩余9条评论

72

类型转换不是一种数学运算,它的行为方式也不像数学运算那样。尝试使用

int y = (int)round(x);

11
无需使用强制类型转换,结果会被隐式转换为 int - Keith Thompson
11
我永远记不住 C 类型提升规则,因此我认为在每个地方明确声明类型转换是没有问题的,因为它们是一个棘手的问题。 - MK.
5
round(),lround()和llround()函数符合ISO/IEC 9899:1999(E)标准。 #include <math.h> - MK.
10
@MK.:这不是晋升,而是隐式转换。赋值、初始化或参数传递将隐式转换任何数字类型为其他数字类型。不必要的强制类型转换可能会有害。例如,n = (int)round(x); 看起来可以,但如果 n 的类型是 long 呢? - Keith Thompson
3
在C99和C++11中,double round (double x); 存在。因此,强制转换确实是必要的。链接:http://www.cplusplus.com/reference/cmath/round/ - Qiangzini
显示剩余4条评论

9

将值转换为 int 会截断其小数部分。添加 0.5 可以进行四舍五入。

int y = (int)(x + 0.5);

20
如上方评论所述,该方法不适用于负数。如果需要,可以使用“floor”函数代替强制类型转换来实现相同的功能。请注意,翻译过程中不能改变原意。 - mehfoos yacoob

5
值得注意的是,你所做的不是四舍五入,而是强制类型转换。使用 (int) x 进行强制类型转换会截取 x 的小数部分。就像你的例子一样,如果 x = 3.9995,则 .9995 被截断,x = 3
正如许多人提出的解决方案,一个解决方法是在 x 上加上 0.5,然后进行强制类型转换。

谢谢,其实我现在才意识到我需要四舍五入(在我的程序中我只使用整数)。 - midnightBlue

-10
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    double x=54.999999999999943157;
    int y=ceil(x);//The ceil() function returns the smallest integer no less than x
    return 0;
}

11
这会使数字增加...54.000000000000001会变成55。 - Albert Renshaw
4
@AlbertRenshaw,正确 - 这意味着这个回答是错误的。 - cp.engr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接