Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » ((0.1f - 0.1f) == (0.1f - 0.1)) == false

Credits go to Hard Rock for helping out!
This thread is locked; no one can reply to it. rss feed Print
((0.1f - 0.1f) == (0.1f - 0.1)) == false
Timorg
Member #2,028
March 2002

I have been working on a program and I came across a problem, in the program I had a variable that should have a value between 0 and 1, with keys making the value step 0.1 a time, but I found the down step from 0.1 to 0 wasn't working correctly.

This is the small code snippet that demonstrate the problem.

#include <iostream>

int main(int argc, char *argv[])
{
  std:: cout << (0.1f - 0.1f) << " = " << (0.1f - 0.1) << std::endl;
  return 0;
}

I have tried this code on

g++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-56)
g++ (GCC) 3.4.2 (mingw-special)
MSVC8 (Version 14.00.50727.42 for 80x86)

and I get the same results in each.

0 = 1.49012e-09

So I guess my question is, what am i misunderstanding, my current solution is to not allow the user to change that value, and work around the issue. But I wish I had a better solution.

-Tim

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Hard Rock
Member #1,547
September 2001
avatar

The problem is that floats don't hold exact numbers. If you tell a float to hold 0.02435325345 it wont hold that exact value, it will hold something very close to it.

This is why in general you should not apply the == operator with floats, since the code for(float f =.1f; f != 0.0; f -= .01f){} will probably go on forever.

What you can do is just check to make sure its in certain bound (eg between a very small difference of what you are looking for) and do it that way.

[edit]
A simple solution in your case is to use integers to store the value and cast + divide by 10.

_________________________________________________
Hard Rock
[ Stars Dev Company ][ Twitter ][Global Warming: ARA My TINS 07 Entry][Pong Ultra Website][GifAllegS Ver 1.07]
"Well there's also coolwebsearch but we'll let that be an IE exclusive feature" - arielb on the New Browser Plugins "What's better, HTML or Variables?"

Timorg
Member #2,028
March 2002

Cookies for Hard Rock.

Your advice worked well, my variable is now 0 to 100, as a percentage, then I cast to float and divide by 100.

Thank you
-Tim

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Carrus85
Member #2,633
August 2002
avatar

Just as an elaboration on what Hard Rock posted above, here is an in-depth explanation of why this happens.

First, 1/10th is a repeating decimal in base 2 (just like 1/3, 1/6, 1/9, etc. in base 10). Illustration:

Long division of 1/3

    0.33
3 | 1.00
     -9
      10
      -9
       1... goes on forever (sorry, it isn't horribly readable...

Long division of 1/10 in base 2

       0.00011001
1010 | 1.00000000
       - 1010
       =  1100
         -1010
       =    10000 ... at this point we have hit a cycle; we will never resolve this evenly.
           - 1010
       =      110

In short, just like <math>1/3 _ {10} = 0.3 \overline{3} _ {10}</math>, <math>1 / 10 _ {10} = 0.00011 \overline{0011} _ 2</math>

Now, as for why you get that weird number for 0.1 - 0.1, first, lets write out the actual IEEE754 float and double representations being used for these values (the first one is assumed, hence the parenthesis, and using round to nearest even, for those interested)
float: 0 01111100 (1)10011001100110011001101 (1.1001100... * 2^-4)
double: 0 01111111100 (1)1001100110011001100110011001100110011001100110011010

Subtract these two: (digits in ()'s are gaurd digits to prevent funky rounding; not really necessary here though)

    1.10011001100110011001101 (000)
   -1.1001100110011001100110011001100110011001100110011010 (000)

(which, can be rewritten as this)

    1.1111111111111111111111 (carries)
    1.10011001100110011001101 00000000000000000000000000000 (000) (extended to double)
+   0.01100110011001100110011 00110011001100110011001100110 (000) (Using 2's compliment)
=   0.00000000000000000000000 00110011001100110011001100110 (000) * 2 ^ -4
=   (1.10011001100110011001100110 * 2 ^ -30 using double.)
=   (1.10011001100110011001101 * 2 ^ -30 using float accuracy. (rounded))

If you convert this result (the double) back to base 10, we arrive at <math>1.59999999404 \times 2 ^ {-30}</math>, which, guess what, is <math>1.49012 \times 10^{-9}</math> when rounded.

Probably a bit longer of an explanation than necessary, but hey, information never hurts.

EDIT: flipped a 6 to a 9 (GHA!)

nonnus29
Member #2,606
August 2002
avatar

Another thread bookmarked for the next 'be friendly to newbs' thread. ;)

edit;

Quote:

Timorg said:
March 2002

Scratch the newb part.

Thomas Harte
Member #33
April 2000
avatar

Quote:

The problem is that floats don't hold exact numbers.

And, lest we forget, they can't hold 0 at all, because 0 can't be written in standard form/scientific notation.

Bob
Free Market Evangelist
September 2000
avatar

Quote:

And, lest we forget, they can't hold 0 at all, because 0 can't be written in standard form/scientific notation.

IEEE-754 floats have 2 complete encodings reserved for encoding 0.

--
- Bob
[ -- All my signature links are 404 -- ]

Andrei Ellman
Member #3,434
April 2003

Carrus85: That's got to be one of the most detailed explanations I've seen of why you shouldn't count in tenths using floats.

AE.

--
Don't let the illegitimates turn you into carbon.

Goalie Ca
Member #2,579
July 2002
avatar

Bob means +0 and -0

-------------
Bah weep granah weep nini bong!

Carrus85
Member #2,633
August 2002
avatar

Just for the record, that range (+0/-0 reserved range) is commonly referred to as Subnormal or Denormal numbers.

Timorg
Member #2,028
March 2002

nonnus29 said:

[quote Timorg]
March 2002

</quote>

Yeah I have been floating around for a little while, the project I am working on at the moment, is for a class where I run the tutes and get the students to use allegro. Last year they did a platform game, this year they are doing a space shooter.

I am working on the example game at the moment that has similarities to Shawn Hargreaves Speed in how the game is projected on the screen, but I have quite a few more features to add. Basically I want to make allegro look as good as possible, so that the students might keep working with allegro after the semester has finished

I am still working on something of a rendering engine, it will be able to change the projection code on the fly, the menu will be drawn flat to the screen, and the game will be played in the circular projection. During load the projection changes.

{"name":"591526 ","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/c\/1c9c8ec1ca0690c3f8b5d0ca252c2365.png","w":262,"h":288,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/1\/c\/1c9c8ec1ca0690c3f8b5d0ca252c2365"}591526 {"name":"591527 ","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/8\/d8c684e2dd4a13fce93b7d9ecdb77a56.png","w":262,"h":288,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/d\/8\/d8c684e2dd4a13fce93b7d9ecdb77a56"}591527
{"name":"591528 ","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/9\/296e89e9442b20017a08207802c60b62.png","w":262,"h":288,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/9\/296e89e9442b20017a08207802c60b62"}591528 {"name":"591529 ","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/a\/0aa16487e3a22a5d72a7ac6b41f4280d.png","w":262,"h":288,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/a\/0aa16487e3a22a5d72a7ac6b41f4280d"}591529

And thanks for a great explanation Carrus85. :D

-Tim

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Go to: