By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,538 Members | 911 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,538 IT Pros & Developers. It's quick & easy.

Comparing floats

P: n/a
I have a function:

int F(double a)
{
if (a = =1.0)
{
return 22;
}
return 44;
}
When I call F(1.0) it returns 22. But if I call F from a loop like:

double a = 0.0;
for (int j = 0; j <= 1000; j++)
{
std::cout << F(a) <<std::endl;
a = a + 0.001;
}

It returns 44 instead when 'a' reaches 1 instead of 22!

After a few hours of messing with my brains I found a website where they say
that comparing floats in C++ is not guranteed to return an expected result.
Instead something like this should be used:

if (fabs(result - expectedResult) < 0.00001)

But before I rewrite all my code that compare floats I would like to hear if
anyone has any better suggestion.
Aug 18 '08 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Sam
saneman writes:
I have a function:

int F(double a)
{
if (a = =1.0)
{
return 22;
}
return 44;
}
When I call F(1.0) it returns 22. But if I call F from a loop like:

double a = 0.0;
for (int j = 0; j <= 1000; j++)
{
std::cout << F(a) <<std::endl;
a = a + 0.001;
}

It returns 44 instead when 'a' reaches 1 instead of 22!
This is because:

1) When internally represented in binary, fractional amounts are irrational.

2) Addition accumulates roundoff errors.

Add the following to your inner loop:

std::cout << a << std::endl;

You'll see what's happening.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEABECAAYFAkiqHNQACgkQx9p3GYHlUOJ76QCfZOmuHBpnr3 NKnTpqiEGN+SYl
+LEAn2v4NZIKi7aCQiuyjGhpU52aOyUS
=mT+9
-----END PGP SIGNATURE-----

Aug 19 '08 #2

P: n/a
saneman wrote:
I have a function:

int F(double a)
{
if (a = =1.0)
{
return 22;
}
return 44;
}
When I call F(1.0) it returns 22. But if I call F from a loop like:

double a = 0.0;
for (int j = 0; j <= 1000; j++)
{
std::cout << F(a) <<std::endl;
a = a + 0.001;
}

It returns 44 instead when 'a' reaches 1 instead of 22!

After a few hours of messing with my brains I found a website where they say
that comparing floats in C++ is not guranteed to return an expected result.
Instead something like this should be used:

if (fabs(result - expectedResult) < 0.00001)
It depends on what you want to do. Most times it is wrong as well. But
this isn't C++ specific; for starters, study the paper "What Every
Computer Scientist Should Know About Floating-Point Arithmetic", by
David Goldberg.

--
Gennaro Prota | name.surname yahoo.com
Breeze C++ (preview): <https://sourceforge.net/projects/breeze/>
Do you need expertise in C++? I'm available.
Aug 19 '08 #3

P: n/a
>This is because:
>
1) When internally represented in binary, fractional amounts are
irrational.

2) Addition accumulates roundoff errors.

Add the following to your inner loop:

std::cout << a << std::endl;

You'll see what's happening.


I have tried doing std::cout << a << std::endl; but it just prints the
numbers from 0.001 to 1 as expected.
Aug 19 '08 #4

P: n/a
Sam
saneman writes:
>>This is because:

1) When internally represented in binary, fractional amounts are
irrational.

2) Addition accumulates roundoff errors.

Add the following to your inner loop:

std::cout << a << std::endl;

You'll see what's happening.

I have tried doing std::cout << a << std::endl; but it just prints the
numbers from 0.001 to 1 as expected.
Probably the precision is not enough. Use std::setw and std::setprecision to
increase the precision shown.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEABECAAYFAkiqqVwACgkQx9p3GYHlUOLihQCfdkVHJBzm5Q c5Dhu07NeXb6zh
2LQAn1M/jz6n9OX2okAqRvtJeQVDMGGo
=vAtO
-----END PGP SIGNATURE-----

Aug 19 '08 #5

P: n/a
saneman wrote:
After a few hours of messing with my brains I found a website where they say
that comparing floats in C++ is not guranteed to return an expected result.
There are a few flaws in that statement:

- This is not related to C++ in particular, but computers in general.
All programming languages which perform direct floating point
comparisons will present the same issue. (Some programming languages
might perform an automatic range comparison behind the scenes, but C++
only does exactly what you tell it to do, nothing more.)

- Whether the result you are seeing is "expected" or not is a question
of definition. For example, assume that I expect this comparison to
return true:

0.3333333 + 0.3333333 + 0.3333333 == 1.0

but instead, it returns false. My expectation was wrong. In fact, the
comparison returning false is what should be expected. Why? Because if
you calculate that sum, you get 0.9999999, which is different from 1.0.
Thus they should obviously compare unequal.

In your example program you are summing 0.001 to itself. However,
computers do not calculate with decimal numbers. They calculate with
base-2 numbers with a limited amount of bits. Base-2 floating point
values with a limited amount of bits cannot represent 0.001 accurately
(for the exact same reason that decimal numbers cannot represent 1/3
accurately).

Thus when you write 0.001, internally the actual value will be just a
tiny bit smaller than that (exactly like 0.333333333333333 is a tiny bit
smaller than 1/3). When you sum that with itself a thousand times, what
you get is 1000 times that a-bit-smaller value, which ends up being
a-bit-smaller than 1.0, which obviously compares unequal to 1.0.

Thus summing 0.001 to itself 1000 times is *expected* to give a result
which is smaller than 1.0 because 0.001 is actually a bit smaller than
what it looks.

(This doesn't mean that no decimal number can be represented
accurately with base-2 floating point numbers. For example 1.0 and 0.5
can be represented accurately, without any rounding off.)

The result of long calculations can accumulate these types of rounding
errors, and thus the result may differ from what an infinitely-accurate
mathematical formula would tell you. Thus you have to make ranged
comparisons.

Another option is to avoid floating point numbers altogether. In many
situations they are just not needed. For example, if you just need all
the values between 0.0 and 1.0, you can do this:

for(int i = 0; i <= 1000; ++i)
someFunctionTakingADouble(i/1000.0);

Now, surprisingly, the last value given to the function will be
exactly 1.0.
Aug 19 '08 #6

This discussion thread is closed

Replies have been disabled for this discussion.