Why do simple doubles like 1.82 end up being 1.819

2019-01-28 20:42发布

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?? Thanks =) ! 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;
}

7条回答
混吃等死
2楼-- · 2019-01-28 21:14

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!

查看更多
【Aperson】
3楼-- · 2019-01-28 21:16

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.

查看更多
在下西门庆
4楼-- · 2019-01-28 21:26

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.

查看更多
可以哭但决不认输i
5楼-- · 2019-01-28 21:30

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

You need to read this, too.

查看更多
来,给爷笑一个
6楼-- · 2019-01-28 21:31

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

查看更多
再贱就再见
7楼-- · 2019-01-28 21:32

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).

查看更多
登录 后发表回答