双类型的舍入问题

时间:2010-10-24 13:25:33

标签: c++ floating-point rounding

  

可能重复:
  Why don't operations on double-precision values give expected results?

我在C ++中遇到了一个奇怪的问题。我创建了一个Double类型的变量。然后我做了一些计算,将一些值分配给其他变量,并将结果分配给我声明的双变量。它给了我一个长小数部分的结果。我希望它只舍入到小数点后2位。并将其存储到变量中。但即使在几次尝试四舍五入之后,我也无法将其舍入到小数点后两位。

然后我尝试了另一种方法来检查真正的问题是什么。我创建了一个Double变量并为其赋值1.11。但是当我通过设置断点并为该变量添加监视来调试它时,我发现现在存储在变量中的值是1.109999999999。

我的问题是,为什么会这样显示?我们有什么方法可以将变量舍入到两位小数?为什么即使我们分配一个只有两位小数的数字,它也会显示一个长小数部分?

请建议一种方法来存储数字 - 无论是计算数字还是直接分配数字 - 实际上是双变量而不是带小数字长的数字。

3 个答案:

答案 0 :(得分:11)

在double值的集合中,没有数字1.11,因为在内部,double使用二进制表示(与用于十进制表示的人相反)。大多数有限十进制数(例如1.11)在二进制中具有无限表示,但由于内存有限,因为舍入而导致精度损失。

使用双数据类型最接近1.11的是1.1100000000000000976996261670137755572795867919921875,其内部表示为0x3ff1c28f5c28f5c3。

您对小数点后两位的要求听起来像是在用钱。一个简单的解决方案是将美分存储在一个整数中(而不是双重中的美元):

int cents = 111;

这样,你不会失去任何精确度。另一种解决方案是使用专用的十进制数据类型。

答案 1 :(得分:4)

float和double等浮点类型不是100%精确。它们可以存储14.3作为14.299999 ......并且没有任何错误。这就是为什么你永远不应该将两个浮点数或双精度数与==运算符进行比较,你应该检查它们的差值的绝对值是否小于某个epsilon,如0.000000001

现在,如果您想以愉快的方式输出数字,可以使用setprecision中的<iomanip>

E.g。

#include <iostream>
#include <iomanip>

int main()
{
   double d = 1.389040598345;
   std::cout << setprecision(2) << d; //outputs 1.39
}

如果你想在点之后获得d舍入2个小数位的值,那么你可以使用这个公式

d = floor((d*100)+0.5)/100.0; //d is now 1.39

答案 2 :(得分:2)

并非每个十进制数都具有精确的有限二进制浮点表示。你已经找到了一个例子,但另一个例子是0.1(十进制)= 0.0001100110011 ...(二进制)。

您需要使用它,或使用十进制浮点库(效率较低)。

我的建议是将数字存储到完全精确度,并且只在需要将数字显示给人类时才进行圆整。