开发者

Why do simple doubles like 1.82 end up being 1.819999999645634565360? [duplicate]

This question already has answers here: Closed 11 years ago.

Possible Duplicate:

Why does Visual Studio 2008 tell me .9 - .8999999999999995 = 0.00000000000000055511151231257827?

c++

Hey so i'm making a function to return the number of a digits in a number data type given, but i'm having some trouble with doubles.

I figure out how many digits are in it by multiplying it by like 10 billion and then taking away digits 1 by 1 until the double ends up being 0. however when putting in a double of value say .7904 i never exit the function as it keeps taking away digits which never end up being 0 as the resut of .7904 ends up being 7,903,999,988 and not 7,904,000,000.

How can i solve this problem?? Thank开发者_如何学Pythons =) ! oh and any other feed back on my code is WELCOME!

here's the code of my function:

///////////////////////     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;
}


It's because of their binary representation, which is discussed in depth here:

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

Basically, when a number can't be represented as is, an approximation is used instead.

To compare floats for equality, check if their difference is lesser than an arbitrary precision.


The easy summary about floating point arithmetic :

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

Read this and you'll see the light.

If you're more on the math side, Goldberg paper is always nice :

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

Long story short : real numbers are stored with a fixed, irregular precision, leading to non obvious behaviors. This is unrelated to the language but more a design choice of how to handle real numbers as a whole.


This is because C++ (like most other languages) can not store floating point numbers with infinte precision.

Floating points are stored like this:
sign * coefficient * 10^exponent if you're using base 10.
The problem is that both the coefficient and exponent are stored as finite integers.

This is a common problem with storing floating point in computer programs, you usually get a tiny rounding error.

The most common way of dealing with this is:

  • Store the number as a fraction (x/y)
  • Use a delta that allows small deviations (if abs(x-y) < delta)
  • Use a third party library such as GMP that can store floating point with perfect precision.

Regarding your question about counting decimals.
There is no way of dealing with this if you get a double as input. You cannot be sure that the user actually sent 1.819999999645634565360 and not 1.82.

Either you have to change your input or change the way your function works.

More info on floating point can be found here: http://en.wikipedia.org/wiki/Floating_point


This is because of the way the IEEE floating point standard is implemented, which will vary depending on operations. It is an approximation of precision. Never use logic of if(float == float), ever!


Float numbers are represented in the form Significant digits × baseexponent(IEEE 754). In your case, float 1.82 = 1 + 0.5 + 0.25 + 0.0625 + ...

Since only a limited digits could be stored, therefore there will be a round error if the float number cannot be represented as a terminating expansion in the relevant base (base 2 in the case).


You should always check relative differences with floating point numbers, not absolute values.

You need to read this, too.


Computers don't store floating point numbers exactly. To accomplish what you are doing, you could store the original input as a string, and count the number of characters.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜