Velocity Reviews > comparison on non-integer types

# comparison on non-integer types

christian.bau
Guest
Posts: n/a

 09-05-2007
On Sep 5, 6:59 pm, Pietro Cerutti <(E-Mail Removed)> wrote:
> Hi group,
> I always thought that applying a binary operator such as ==, !=, <= or>= to two double or float values was an operation which results were
>
> well defined.
>
> Now, I'm passing a program through splint[1] and it says:
>
> Dangerous equality comparison involving double types:
> l_lnk1->lnk_freq == l_lnk2->lnk_freq
> Two real (float, double, or long double) values are compared directly
> using == or != primitive. This may produce unexpected results since
> floating point representations are inexact. Instead, compare the
> difference to FLT_EPSILON or DBL_EPSILON.
>
> l_lnk1->lnk_freq and l_lnk2->lnk_freq being defined as double values.
>
> Is it really better to write the comparison as
> (l_lnk1->lnk_freq - l_lnk2->lnk_freq < DBL_EPSILON)
> or is splint being over-pedantic in this situation?

It is more complicated.

For a good floating-point implementation, comparing two floating point
numbers for equality is perfectly safe. The result will be 1 if they
are equal and 0 if they are not equal. And there are the special cases
that +0 == -0 and NaN !- NaN.

That will tell you that two floating-point numbers are equal. That,
however, may or may not be what you wanted to know. For example, 1.0 /
3.0 + 2.0 / 3.0 == 1.0 and 1.0 + 1e-20 == 1.0 may or may not give the
result you expect. Just because you think two floating point numbers
should be the same/different, doesn't mean they are.

Now lets say you write a compiler, and you need to keep track of all
different floating point numbers used in a program. You better compare
for equality, and don't do anything stupid with DBL_EPSILON and the
like. Or you want to sort an array of numbers: Are you sure your
sorting algorithm will work if a == b and b == c but a != c? As soon
as you go down the route of checking whether numbers are nearby
instead of equal, you just have to be very careful.

Mark McIntyre
Guest
Posts: n/a

 09-05-2007
On Wed, 05 Sep 2007 12:54:19 -0700, in comp.lang.c , Keith Thompson
<(E-Mail Removed)> wrote:

>Mark McIntyre <(E-Mail Removed)> writes:
>> On Wed, 05 Sep 2007 20:43:45 +0200, in comp.lang.c , Pietro Cerutti
>> <(E-Mail Removed)> wrote:
>>
>> Defined and guaranteed are different.
>>

(snip my idiocy)
>
>The result is 1 if the arguments are identical, 0 otherwise.

D'oh! of course it is. Gak.

>accumulated roundoff errors can become arbitrarily large, depending on

mhm - involve logs and powers somewhere, and watch 'em multiply.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan

Keith Thompson
Guest
Posts: n/a

 09-05-2007
Mark McIntyre <(E-Mail Removed)> writes:
> On Wed, 05 Sep 2007 12:54:19 -0700, in comp.lang.c , Keith Thompson
> <(E-Mail Removed)> wrote:

[...]
>>accumulated roundoff errors can become arbitrarily large, depending on

>
> mhm - involve logs and powers somewhere, and watch 'em multiply.

sin(1e100)

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

pete
Guest
Posts: n/a

 09-06-2007
Pietro Cerutti wrote:

> printf("%lf and %lf are %sequal\n", a, b, (DBL_CMP(a,b)) ? " " : un");

Try real hard to use copy and paste,
or something just like copy and paste,
instead of purporting to have posted a program that you ran.

--
pete

pete
Guest
Posts: n/a

 09-06-2007
Pietro Cerutti wrote:
>
> Hi group,
> I always thought that applying a binary operator such as ==, !=, <= or
> >= to two double or float values was an operation which results were

> well defined.
>
> Now, I'm passing a program through splint[1] and it says:
>
> Dangerous equality comparison involving double types:
> l_lnk1->lnk_freq == l_lnk2->lnk_freq
> Two real (float, double, or long double) values are compared directly
> using == or != primitive. This may produce unexpected results since
> floating point representations are inexact. Instead, compare the
> difference to FLT_EPSILON or DBL_EPSILON.
>
> l_lnk1->lnk_freq and l_lnk2->lnk_freq being defined as double values.
>
> Is it really better to write the comparison as
> (l_lnk1->lnk_freq - l_lnk2->lnk_freq < DBL_EPSILON)
> or is splint being over-pedantic in this situation?

I agree with christian.bau's statement: "It is more complicated.";
and also with Flash Gordon's
"It is best to understand the real issues
and then make an appropriate decision

If you take a look at the math functions at
http://www.mindspring.com/~pfilandr/C/fs_math/fs_math.c
the !=, ==, >=, and > operators
are all used to compare double values,
but as far as I can tell, the usage is appropriate.

In the same file,
there are also examples where DBL_EPSILON needs to be, and is, used.

--
pete

user923005
Guest
Posts: n/a

 09-06-2007
On Sep 5, 11:20 am, Flash Gordon <(E-Mail Removed)> wrote:
> Pietro Cerutti wrote, On 05/09/07 18:59:
>
>
>
>
>
> > Hi group,
> > I always thought that applying a binary operator such as ==, !=, <= or
> > > = to two double or float values was an operation which results were

> > well defined.

>
> > Now, I'm passing a program through splint[1] and it says:

>
> > Dangerous equality comparison involving double types:
> > l_lnk1->lnk_freq == l_lnk2->lnk_freq
> > Two real (float, double, or long double) values are compared directly
> > using == or != primitive. This may produce unexpected results since
> > floating point representations are inexact. Instead, compare the
> > difference to FLT_EPSILON or DBL_EPSILON.

>
> > l_lnk1->lnk_freq and l_lnk2->lnk_freq being defined as double values.

>
> > Is it really better to write the comparison as
> > (l_lnk1->lnk_freq - l_lnk2->lnk_freq < DBL_EPSILON)
> > or is splint being over-pedantic in this situation?

>
> It is best to understand the real issues and then make an appropriate
> decision based on your particular situation.
>
> The basic problem is that computers are finite. Therefore when working
> with float or double you tend to get only approximate results. Exactly
> what you are doing with them and the vagaries of your particular
> implementation will determine how fast and in what direction those
> errors grow. Then there is the question of whether it is better for your
> equality test to return true for numbers that theoretically should be
> different or false for numbers that theoretically be equal.
>
> I suggest you look at the section of the comp.lang.c FAQ athttp://c-faq.com/that is all about floating point numbers. It is by no
> means exhaustive, but it is a start.

I believe I have posted this before:

#include <float.h>
#include <math.h>

int double_compare (double d1, double d2)
{
if (d1 > d2)
if ((d1 - d2) < fabs (d1 * DBL_EPSILON))
return 0;
else
return 1;
if (d1 < d2)
if ((d2 - d1) < fabs (d2 * DBL_EPSILON))
return 0;
else
return -1;
return 0;
}

int float_compare (float d1, float d2)
{
if (d1 > d2)
if ((d1 - d2) < fabsf (d1 * FLT_EPSILON))
return 0;
else
return 1;
if (d1 < d2)
if ((d2 - d1) < fabsf (d2 * FLT_EPSILON))
return 0;
else
return -1;
return 0;
}

CBFalconer
Guest
Posts: n/a

 09-06-2007
Pietro Cerutti wrote:
>
> I always thought that applying a binary operator such as ==, !=,
> <= or >= to two double or float values was an operation which
> results were well defined.
>
> Now, I'm passing a program through splint[1] and it says:
>
> Dangerous equality comparison involving double types:
> l_lnk1->lnk_freq == l_lnk2->lnk_freq
> Two real (float, double, or long double) values are compared
> directly using == or != primitive. This may produce unexpected
> results since floating point representations are inexact.
> Instead, compare the difference to FLT_EPSILON or DBL_EPSILON.
>
> l_lnk1->lnk_freq and l_lnk2->lnk_freq being defined as double
> values.
>
> Is it really better to write the comparison as
> (l_lnk1->lnk_freq - l_lnk2->lnk_freq < DBL_EPSILON)
> or is splint being over-pedantic in this situation?

Your expression is over-simplified. You have to take the absolute
value of the difference, and then you also have to scale either
that of DBL_EPSILON to the items compared.

Try to arrange your code to depend on <, >, <=, >= only.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

--
Posted via a free Usenet account from http://www.teranews.com

pete
Guest
Posts: n/a

 09-06-2007
user923005 wrote:
>
> On Sep 5, 11:20 am, Flash Gordon <(E-Mail Removed)> wrote:

> > The basic problem is that computers are finite.
> > Therefore when working
> > with float or double you tend to get only approximate results.
> > Exactly what you are doing with them
> > and the vagaries of your particular
> > implementation will determine how fast and in what direction those
> > errors grow. Then there is the question of
> > whether it is better for your
> > equality test to return true for numbers
> > that theoretically should be
> > different or false for numbers that theoretically be equal.
> >
> > I suggest you look at
> > the section of the comp.lang.c FAQ at
> > http://c-faq.com/that is all about floating point numbers.
> > It is by no means exhaustive, but it is a start.

>
> I believe I have posted this before:
>
> #include <float.h>
> #include <math.h>
>
> int double_compare (double d1, double d2)
> {
> if (d1 > d2)
> if ((d1 - d2) < fabs (d1 * DBL_EPSILON))
> return 0;
> else
> return 1;
> if (d1 < d2)
> if ((d2 - d1) < fabs (d2 * DBL_EPSILON))
> return 0;
> else
> return -1;
> return 0;
> }
>
> int float_compare (float d1, float d2)
> {
> if (d1 > d2)
> if ((d1 - d2) < fabsf (d1 * FLT_EPSILON))
> return 0;
> else
> return 1;
> if (d1 < d2)
> if ((d2 - d1) < fabsf (d2 * FLT_EPSILON))
> return 0;
> else
> return -1;
> return 0;
> }

That way, it's possible to have a number
which compares equal to two other numbers,
which do not compare equal to each other.

There's no place for EPSILON's
if you're writing a qsort compar function for an array of floats.

--
pete

Guest
Posts: n/a

 09-06-2007
Mark McIntyre wrote:
> On Wed, 05 Sep 2007 19:59:42 +0200, in comp.lang.c , Pietro Cerutti
> <(E-Mail Removed)> wrote:
>
>> Hi group,
>> I always thought that applying a binary operator such as ==, !=, <= or
>>> = to two double or float values was an operation which results were

>> well defined.

>
> Er, no.

The comparisons are well defined and, in my experience, yield
predictable results. The problem is not accounting for the variation
caused by rounding of intermediate results and approximations of
transcendental functions used to calculate the operands being compared.
In the past I used long double to successfully manipulate integers
that didn't fit into the largest native integer type (long).

> In real world situations I've seen live systems fall over because
> comparisons like
>
> if (x >= 100.00)
>
> failed when x was retrieved from a database, even when the database
> admin tools told me the value stored was 100.0000000000.

Let's be careful out there...

--

Guest
Posts: n/a

 09-06-2007
On Wed, 05 Sep 2007 21:06:32 -0400, CBFalconer wrote:

> Pietro Cerutti wrote:
>>
>> I always thought that applying a binary operator such as ==, !=,
>> <= or >= to two double or float values was an operation which
>> results were well defined.
>>

<snip>
>
> Try to arrange your code to depend on <, >, <=, >= only.
>

<snip>
Are you saying that "(a<=b) && (b<=a)" is ok but that "(a==b)"
is dangerous?