Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

testing float values for equality

1 view
Skip to first unread message

John A. Grant

unread,
May 27, 1999, 3:00:00 AM5/27/99
to
I have some simple code that sets an initial value of
MAXFLOAT (<values.h>). During the processing, this might
get set to some other value or perhaps not. At the end I need
to know if it is still MAXFLOAT.

For various reasons, it's not possible to set a flag or use some
other variable. I need to test the floating-point value itself.

I'm well acquainted with the technique of comparing 2 float
values for equality by taking the difference and comparing it
to epsilon, i.e.:
#include <float.h>
#define FEQUAL(x,y) (fabs((x)-(y))<=FLT_EPSILON)

This has served me well for many years, but it's not working
for MAXFLOAT.

Here's some test code:
#include <stdio.h>
#include <values.h>

int main(int argc,char **argv){
float x=MAXFLOAT;
printf("x: %g\n",x);
printf("x -MAXFLOAT: %g\n",x-MAXFLOAT);
return(0);
}

The output I get is:
x: 3.37e+38
x -MAXFLOAT: 3.72755e+30

Now I can see why the above FEQUAL macro won't work - the
difference between the 2 values is nowhere near 0. Why?

So what's a good way to test for 'x==MAXFLOAT'?

--
John A. Grant * I speak only for myself * (remove 'z' to reply)
Airborne Geophysics, Geological Survey of Canada, Ottawa
If you followup, please do NOT e-mail me a copy: I will read it here


Horst Kraemer

unread,
May 27, 1999, 3:00:00 AM5/27/99
to
On Thu, 27 May 1999 02:32:12 -0400, "John A. Grant"
<zjag...@znrcanz.gcz.ca> wrote:

> I have some simple code that sets an initial value of
> MAXFLOAT (<values.h>). During the processing, this might
> get set to some other value or perhaps not. At the end I need
> to know if it is still MAXFLOAT.

> For various reasons, it's not possible to set a flag or use some
> other variable. I need to test the floating-point value itself.

> I'm well acquainted with the technique of comparing 2 float
> values for equality by taking the difference and comparing it
> to epsilon, i.e.:
> #include <float.h>
> #define FEQUAL(x,y) (fabs((x)-(y))<=FLT_EPSILON)
>
> This has served me well for many years, but it's not working
> for MAXFLOAT.

Sorry, but as a general "technique" for comparing floats this makes no
sense and FLT_EPSILON is not meant to be used like this. In typical
IEEE implementations FLT_EPSILON ~ 1E-7

This would mean that 1E-10 is 'FEQUAL' to 1E-20 although the first is
10 billion times bigger than the latter...


> Here's some test code:
> #include <stdio.h>
> #include <values.h>
>
> int main(int argc,char **argv){
> float x=MAXFLOAT;
> printf("x: %g\n",x);
> printf("x -MAXFLOAT: %g\n",x-MAXFLOAT);
> return(0);
> }
>
> The output I get is:
> x: 3.37e+38
> x -MAXFLOAT: 3.72755e+30
>
> Now I can see why the above FEQUAL macro won't work - the
> difference between the 2 values is nowhere near 0. Why?

You were unlucky because you are using a buggy implementation of
<value.h>, probably a Borland Compiler.

In your implementation MAXFLOAT is defined by a decimal string like

#define MAXFLOAT 3.37E38

The literal string "3.37e38" is a constant of type 'double'. Its
double value will be converted to float by the assignment to x. This
includes some kind of rounding. Now the expression

x - MAXFLOAT

is an expression of type double because MAXFLOAT is a double. it is
evaluated as

(double)x - MAXFLOAT

and (double)(float)MAXFLOAT != MAXFLOAT.

If you replace x-MAXFLOAT by x-(float)MAXFLOAT or if you assign
previously

const float m = MAXFLOAT;
float x = m; /* or MAXFLOAT */

then

x-(float)MAXFLOAT

or

x-m

will display 0.

There is a better solution, of course. Instead of the non-standard
header <values.h> include the standard header <float.h> and use
FLT_MAX (<float.h>) instead of MAXFLOAT.

Then

x == FLT_MAX

will be true if x was never changed.


Regards
Horst


Martin Ambuhl

unread,
May 27, 1999, 3:00:00 AM5/27/99
to
"John A. Grant" wrote:
>
> I have some simple code that sets an initial value of
> MAXFLOAT (<values.h>). During the processing, this might
> get set to some other value or perhaps not. At the end I need
> to know if it is still MAXFLOAT.

You might start by using the standard value FLT_MAX from the standard header
<float.h> instead of the non-standard value and header you are using.

>
> For various reasons, it's not possible to set a flag or use some
> other variable. I need to test the floating-point value itself.
>
> I'm well acquainted with the technique of comparing 2 float
> values for equality by taking the difference and comparing it
> to epsilon, i.e.:
> #include <float.h>
> #define FEQUAL(x,y) (fabs((x)-(y))<=FLT_EPSILON)

The largest value smaller than FLT_MAX should be
FLT_MAX/(1.+FLT_EPSILON)
So, why not
#define CHANGED(x) ((x) <= FLT_MAX/(1.+FLT_EPSILON))


--
Martin Ambuhl (mam...@earthlink.net)
Note: mam...@tiac.net will soon be inactive


Christian Bau

unread,
May 27, 1999, 3:00:00 AM5/27/99
to
In article <7iiove$1b...@nrn2.NRCan.gc.ca>, "John A. Grant"
<zjag...@znrcanz.gcz.ca> wrote:

> I have some simple code that sets an initial value of
> MAXFLOAT (<values.h>). During the processing, this might
> get set to some other value or perhaps not. At the end I need
> to know if it is still MAXFLOAT.
>

> So what's a good way to test for 'x==MAXFLOAT'?

x == MAXFLOAT.

The == operator will produce 1 if the numbers are equal, and 0 if they are
not equal. Of course, if the same value is calculated in two different
ways, you might get different results, so (1.0 / 3.0) * 3.0 == 1.0 might
be false, but that means just that: The result of calculating (1.0 / 3.0)
* 3.0 is not 1.0.

The point is: The == operator tells you whether values are equal. Very
often this is not what you really want; you often want to know whether two
values are very close. But here you want to know whether they are equal:
Use ==.

John A. Grant

unread,
May 27, 1999, 3:00:00 AM5/27/99
to
Horst Kraemer wrote in message <374d4908....@news.snafu.de>...

>On Thu, 27 May 1999 02:32:12 -0400, "John A. Grant"
[...]

>Sorry, but as a general "technique" for comparing floats this makes no
>sense and FLT_EPSILON is not meant to be used like this. In typical
>IEEE implementations FLT_EPSILON ~ 1E-7
>
>This would mean that 1E-10 is 'FEQUAL' to 1E-20 although the first is
>10 billion times bigger than the latter...

I would never try to calculate a number and test it for equality
with a number like "12345" using:
float x=...some expression...;
if(x==12345f) printf("equal");

What I really want to know is whether it's close to 12345 and
close to me means having a difference <=FLT_EPSILON, so
in that case, it seems to be a reasonable method of
comparison.

However, it's a different process to assign a number:
float x=12345f;

and then later test to see if it still has that same value:
if(x==12345f)

In this case, it should work just fine, provided the precision
of the constant matches the precision of the variable type.
My mistake was overlooking the fact that MAXFLOAT was
a double.

>You were unlucky because you are using a buggy implementation of
><value.h>, probably a Borland Compiler.

Yup, you guessed it - Borland.

[...]

>There is a better solution, of course. Instead of the non-standard
>header <values.h> include the standard header <float.h> and use
>FLT_MAX (<float.h>) instead of MAXFLOAT.
>
>Then
>
> x == FLT_MAX
>
>will be true if x was never changed

Yup, standard headers are always a better idea. Good point.
I'll use FLT_MAX.

Horst Kraemer

unread,
Jun 11, 1999, 3:00:00 AM6/11/99
to
On Thu, 27 May 1999 23:21:21 -0400, "John A. Grant"
<zjag...@znrcanz.gcz.ca> wrote:

> Horst Kraemer wrote in message <374d4908....@news.snafu.de>...
> >On Thu, 27 May 1999 02:32:12 -0400, "John A. Grant"
> [...]
>
> >Sorry, but as a general "technique" for comparing floats this makes no
> >sense and FLT_EPSILON is not meant to be used like this. In typical
> >IEEE implementations FLT_EPSILON ~ 1E-7
> >
> >This would mean that 1E-10 is 'FEQUAL' to 1E-20 although the first is
> >10 billion times bigger than the latter...
> I would never try to calculate a number and test it for equality
> with a number like "12345" using:
> float x=...some expression...;
> if(x==12345f) printf("equal");
>
> What I really want to know is whether it's close to 12345 and
> close to me means having a difference <=FLT_EPSILON, so
> in that case, it seems to be a reasonable method of
> comparison.


Sorry, if my reply is late.

No. Definitely not. Assuming FLT_EPSiLON ~ 1E-7, this means that your
numbers _have_ only 7 digits.

If you test


if ( fabs(x-12345)<FLT_EPSILON )

Then the candidates for testing around 12345.00 are

........
12344.98
12344.99
12345.00
12345.01
12345.02
........

There is no possible float value in between these step values.
Thus, as FLT-EPSILON is 0.0000001, the comparison will _never_ yield
'false' for any value but _exaxtly_ 12345.

Thus

if ( fabs(x-12345)<FLT_EPSILON )

is equivalent to

if ( x==12345 )

Therefore a useful test could be

if ( fabs(x-12345) < 12345*5*FLT_EPSILON )

which would report as "equal" all numbers between 12344.95 and
12345.05.

The threshold '12345*5*FLT_EPSILON' would denote something like

"5 units of the least significant digit of the values around 12345".

Note that the unit of the least significant digit is 'floating'
according to the magnitude of the value whereas FLT_EPSILON denotes
the unit of the least significant digit for values near 1.0.

Regards
Horst


0 new messages