2

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;
}
Community
  • 1
  • 1
Griffin
  • 2,399
  • 7
  • 48
  • 83

7 Answers7

2

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.

Denis de Bernardy
  • 75,850
  • 13
  • 131
  • 154
2

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.

Joel Falcou
  • 6,247
  • 1
  • 17
  • 34
1

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

Nicklas A.
  • 6,501
  • 7
  • 40
  • 65
1

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!

Nektarios
  • 10,173
  • 8
  • 63
  • 93
  • Actually, one way of testing for convergence in floating point calculations is `a + b == a`. Then you know that `b` is small enough to be ignored. – Ted Hopp May 15 '11 at 03:17
1

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

xiao 啸
  • 6,350
  • 9
  • 40
  • 51
0

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

You need to read this, too.

duffymo
  • 305,152
  • 44
  • 369
  • 561
0

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.

Sam Magura
  • 850
  • 8
  • 18
  • you mean with ltoa()? I am not fond of this function as it is not very simple and requres me to work with non-constant char arrays.... What do you suggest to accomplish this? – Griffin May 15 '11 at 04:05
  • Sorry, I'm not a C/C++ person, so I don't know how specifically to do it – Sam Magura May 15 '11 at 04:46