为什么简单的双打如1.82最终成为1.819999999645634565360?

时间:2011-05-15 02:54:30

标签: c++ double precision

  

可能重复:
  Why does Visual Studio 2008 tell me .9 - .8999999999999995 = 0.00000000000000055511151231257827?

C ++

嘿所以我正在创建一个函数来返回给定数字数据类型中的数字位数,但是我在使用双打时遇到了一些麻烦。

我通过将它乘以100亿,然后将数字1乘以1直到双数结束为0来计算其中有多少位数。但是当输入一个双倍的值时,说.7904我永远不会退出功能因为它一直带走从未结束为0的数字,因为.7904的最终结果为7,903,999,988而不是7,904,000,000。

我该如何解决这个问题?谢谢=)!哦,我的代码上的任何其他反馈都是WELCOME!

这是我的功能代码:

///////////////////////     Numb_Digits()   ////////////////////////////////////////////////////
        enum{DECIMALS = 10, WHOLE_NUMBS = 20, ALL = 30};
    template<typename T>
unsigned long int Numb_Digits(T numb, int scope)
{
        unsigned long int length= 0; 
    switch(scope){
        case DECIMALS:      numb-= (int)numb;   numb*=10000000000; // 10 bil (10 zeros)
            for(; numb != 0; length++)
                numb-=((int)(numb/pow((double)10, (double)(9-length))))* pow((double)10, (double)(9-length)); break;

        case WHOLE_NUMBS:   numb= (int)numb;    numb*=10000000000; 
            for(; numb != 0; length++)
                numb-=((int)(numb/pow((double)10, (double)(9-length))))* pow((double)10, (double)(9-length)); break;

        case ALL:           numb = numb;        numb*=10000000000;
            for(; numb != 0; length++)
                numb-=((int)(numb/pow((double)10, (double)(9-length))))* pow((double)10, (double)(9-length)); break;

        default: break;}
                                            return length;
};

int main()
{
    double test = 345.6457;
    cout << Numb_Digits(test, ALL) << endl; 
    cout << Numb_Digits(test, DECIMALS) << endl;
    cout << Numb_Digits(test, WHOLE_NUMBS) << endl;

    return 0;
}

7 个答案:

答案 0 :(得分:2)

这是因为他们的二进制表示,这里将深入讨论:

http://en.wikipedia.org/wiki/IEEE_754-2008

基本上,当一个数字不能用表示时,会使用近似值。

要比较浮点数是否相等,请检查它们的差异是否小于任意精度。

答案 1 :(得分:2)

关于浮点运算的简单总结:

http://floating-point-gui.de/

阅读本文,你会看到光明。

如果你更喜欢数学方面,Goldberg的论文总是很好:

http://cr.yp.to/2005-590/goldberg.pdf

长话短说:实数以固定的,不规则的精度存储,导致不明显的行为。这与语言无关,但更多的是如何处理整个实数的设计选择。

答案 2 :(得分:1)

这是因为C ++(像大多数其他语言一样)无法存储具有infinte精度的浮点数。

浮点数存储如下:
sign * coefficient * 10^exponent如果你使用的是基数10 问题是coefficientexponent都存储为有限整数。

这是在计算机程序中存储浮点的常见问题,通常会出现一个很小的舍入错误。

解决这个问题最常见的方法是:

  • 将数字存储为分数(x / y)
  • 使用允许小偏差的增量(如果abs(x-y)
  • 使用GMP等第三方库,可以精确存储浮点数。

关于计算小数的问题 如果你得到一个双输入,就无法解决这个问题。您无法确定用户是否实际发送了1.819999999645634565360而不是1.82。

您必须更改输入或更改功能的工作方式。

有关浮点的更多信息,请访问:http://en.wikipedia.org/wiki/Floating_point

答案 3 :(得分:1)

这是因为IEEE浮点标准的实现方式,具体取决于操作。它是精度的近似值。 从不使用if(float == float)的逻辑,永远!

答案 4 :(得分:1)

浮点数以重要数字×baseexponent(IEEE 754)的形式表示。在您的情况下,浮动1.82 = 1 + 0.5 + 0.25 + 0.0625 + ...

由于只能存储有限的数字,因此如果浮点数不能表示为相关基数中的终止扩展(在该情况下为基数2),则会出现舍入错误。

答案 5 :(得分:0)

您应该始终检查浮点数的相对差异,而不是绝对值。

您也需要阅读this

答案 6 :(得分:0)

计算机不会准确存储浮点数。要完成您正在进行的操作,您可以将原始输入存储为字符串,并计算字符数。