浮点算术的最佳实践

我正在对小数点输入执行加法和减法,精确到小数点后第二位。 我试图通过乘以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