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