Assigning floats using precision (funny example)

J

jonas.email

Im am doing a major project and after a long time debugging i found
this rather funny (=annoying) bug. In its simple form, this is the main
problem:

int main(void) {
float f1 = 0.3f;
float f2 = 0.1f;
printf("%f, %.10f, %f, %.10f\n", f1, f1, f2, f2);

if(f1 == 3*f2)
printf("%f == 3*%f\n", f1, f2);

if(f1 == 3.f*f2)
printf("%f == 3.0*%f\n", f1, f2);

return 0;
}

Output: 0.300000, 0.3000000119, 0.100000, 0.1000000015

Using MS Visual Studio 6 on a Windows XP box

So the problem is, that i need to do a more precise assignment of the
float variables, because the variable f1 is not 0.3 (and f2 is not 0.2)
but bigger. But how?
 
V

Victor Bazarov

Im am doing a major project and after a long time debugging i found
this rather funny (=annoying) bug.

It's not a bug.
In its simple form, this is the main
problem:

int main(void) {
float f1 = 0.3f;
float f2 = 0.1f;
printf("%f, %.10f, %f, %.10f\n", f1, f1, f2, f2);

if(f1 == 3*f2)
printf("%f == 3*%f\n", f1, f2);

if(f1 == 3.f*f2)
printf("%f == 3.0*%f\n", f1, f2);

return 0;
}

Output: 0.300000, 0.3000000119, 0.100000, 0.1000000015

Using MS Visual Studio 6 on a Windows XP box

So the problem is, that i need to do a more precise assignment of the
float variables, because the variable f1 is not 0.3 (and f2 is not 0.2)
but bigger. But how?

Use 'double'.

V
 
J

jonas.email

No sorry it's not a bug - but an error in my program. But the problem
is, that i need to check if the sum of two floats are greater than a
third float, and the floats do not have more than two dicimals! For
that purpose i do not need double - the float should be the right type!
 
V

Victor Bazarov

No sorry it's not a bug - but an error in my program. But the problem
is, that i need to check if the sum of two floats are greater than a
third float, and the floats do not have more than two dicimals! For
that purpose i do not need double - the float should be the right type!

Look up "What Every Computer Scientist Should Know About Floating-Point
Arithmetic" on the Web. Read it. If some questions remain, ask them.

V
 
V

velthuijsen

This happens because a floating point value tries to stuff (within a
set of boundaries, look for FLT_MAX, FLT_MIN) an unlimited number of
numbers in a 32 bit space. This means that not all numbers can be
represented exactly.
To counter this a value is used to denote a cut-off point after which
you declare that two floating point values differing less then that
cut-off value are equal. MSVC++ gives you a suggestion for this value
(FLT_EPSILON) for which if you add it to 1 you get a new value. So
1.0+FLT_EPSILON != 1.0
Note that this value is only really usuable for 1.0 and has to be
tweaked to fit the biggest floating point value you are using and the
amount of mathematical actions you perform on this value.

That is why I rather use another solution which might not be portable
to all OSes/compilers so test with care (the double version is
definately not portable due to no standards on a 64 bit integer).
IIRC MSVC++ 6 is IEEE 754 compliant.
That means you can do:
float FloatingPointValue1 = 0.3f,
FloatingPointValue2 = 0.1f*3.0f;
int ULPS = 2048;
if ((int)FloatingPointValue1 > ((int)FloatingPointValue2-ULPS) &&
(int)FloatingPointValue1 < ((int)FloatingPointValue2+ULPS))
{
printf("FloatingPointValue1 == FloatingPointValue2\n");
}

This works because the sign bit and the 8 exponent bits are
the most significant part of the value (according to IEEE 754).
So if you chose ULPS (for units in last place) ranging from 0 to 2^23-1
you are effectively saying how big of a difference between two floating
point values to ignore.

You still need to select the ULPS value with care (how much precision
do you want to retain, how much do you expect to lose in math, etc.)
but you lost the influence of the exponent on how big the epsilon
value should be.

The good thing about this trick is that you automatically check for
sign bit and due to the restrictions placed by 754 on how a floating
points are build up a difference in the exponent automatically means
that two values are not the same.

P.s. use include <iostream> instead of <stdio.h> and feed your output
to std::cout.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top