浮点算术的最佳实践
我正在对小数点输入执行加法和减法,精确到小数点后第二位。 我试图通过乘以100将它们转换为整数来提高准确度,但却达到了相反的效果。
请考虑以下代码和输出:
double d = 2.01; int a = (int) (d * 100.0); cout << a << endl;
输出是:
200
一劳永逸,关于浮点算术的一些最佳实践是什么? 首先使用上面代码的一些变体将double
转换为int
,然后将其转换回来是否可行?
如果将d*100.0
的结果打印到(例如)20位小数,问题将很快变得明显:
200.99999999999997
由于那(小得多)小于201,当你转换为int
时它会被截断为200。
显而易见的解决方法是强制四舍五入。 至少如果你的输入都是正数,那么就像在结果中加0.5一样简单:
int a = (int)(d*100.0 + 0.5);
如果你可以指望你的编译器支持它,那么使用标准库的round
会更容易:
long a = lround(d*100.0);
这适用于正数和负数。
使用标准数学库的舍入函数。 在C ++中,这意味着您必须#include
并使用-lm
编译。
然后,为您的例子:
double d = 2.01; long x = lround(d*100); cout << x << endl; // prints 201, for sure.
这与“添加.5”技巧相同,但它对正数和负数都能正常工作。
阅读本文并达成启示:
每个计算机科学家应该知道的浮点运算
浮点算术被许多人认为是一个深奥的主题。 这是相当令人惊讶的,因为浮点在计算机系统中无处不在。 几乎每种语言都有浮点数据类型; 从PC到超级计算机的计算机都有浮点加速器; 大多数编译器都会被要求不时编译浮点算法; 几乎每个操作系统都必须响应溢出等浮点exception。 本文提供了一个关于浮点的那些方面的教程,这些方面对计算机系统的设计者有直接影响。 它首先介绍浮点表示和舍入错误,继续讨论IEEE浮点标准,最后总结了许多计算机构建器如何更好地支持浮点数的例子。
为了得到明确的路由,我会使用floor()和ceil()。
因此,对于以下代码,
(int)floor( 2.01*100.)
我明白了:
200
但对于:
(int)ceil(2.01*100.)
我明白了:
201