# Writing a macro for checking close enough floating points.

Discussion in 'C Programming' started by pereges, Jun 29, 2008.

1. ### peregesGuest

Hi, I'm trying to write a macro for the relative difference function
which is used to check the close enough floating point values. Is
this correct way to write it ? :

#define max(x, y) ((x) > (y) ? (x) : (y))
#define eq(a, b) max(fabs(a), fabs(b)) == 0.0 ? 0.0 : fabs(a - b) /
(max(fabs(a), fabs(b)))

pereges, Jun 29, 2008

2. ### Walter RobersonGuest

In article <>,
pereges <> wrote:
>Hi, I'm trying to write a macro for the relative difference function
>which is used to check the close enough floating point values. Is
>this correct way to write it ? :

>#define max(x, y) ((x) > (y) ? (x) : (y))
>#define eq(a, b) max(fabs(a), fabs(b)) == 0.0 ? 0.0 : fabs(a - b) /
>(max(fabs(a), fabs(b)))

The name eq() suggests a logical test. Logical tests in C return
an integral 0 or an integral 1. Your macro returns a floating 0.0
or some other floating point calculation (which might be floating 0.0
if the two values are equal but non-0.) Using a logical name for a test
but returning a floating point value suggests that you have some
confusion about how this macro is going to be used.

Also, consider that in the eq() macro that the arguments might be
expressions. Unless subtraction is the lowest precedence operator
(and it isn't), fabs(a - b) is not going to be correct if a or b
are expressions of lower precedence. Take the hint from the way that
the x and y arguments are used in max().

I have not attempted a numeric analysis to determine what
--
"The quirks and arbitrariness we observe force us to the
conclusion that ours is not the only universe." -- Walter Kistler

Walter Roberson, Jun 29, 2008

3. ### August KarlstromGuest

pereges wrote:
> Hi, I'm trying to write a macro for the relative difference function
> which is used to check the close enough floating point values. Is
> this correct way to write it ? :
>
>
> #define max(x, y) ((x) > (y) ? (x) : (y))
> #define eq(a, b) max(fabs(a), fabs(b)) == 0.0 ? 0.0 : fabs(a - b) /
> (max(fabs(a), fabs(b)))

Are you sure you really need to define the functions as macros? If you
define them as ordinary functions they can typically be inlined by the
compiler anyway. This way you will also have type safety. I would write
something like the following:

#include <assert.h>
#include <math.h>

double max(double x, double y)
{
return (x > y)? x: y;
}

double reldiff(double x, double y)
{
assert((x != 0) || (y != 0));

return fabs(x - y) / max(fabs(x), fabs(y));
}

August

August Karlstrom, Jun 29, 2008
4. ### peregesGuest

On Jun 29, 7:17 pm, August Karlstrom <> wrote:

> Are you sure you really need to define the functions as macros? If you
> define them as ordinary functions they can typically be inlined by the
> compiler anyway. This way you will also have type safety. I would write
> something like the following:
>
> #include <assert.h>
> #include <math.h>
>
> double max(double x, double y)
> {
> return (x > y)? x: y;
>
> }
>
> double reldiff(double x, double y)
> {
> assert((x != 0) || (y != 0));
>
> return fabs(x - y) / max(fabs(x), fabs(y));
>
> }

Is it always better to write functions over macros for even smaller
things, say square of a number ?
For my project, I have a file called util.h which basically contains
some math macros like this, error display macro, constants etc. all at
one place and its a few lines anyway so including it in most files
won't hurt that bad whereas if i write full fledge functions it
increases the amount of code that is included everytime. Is that
correct ?

pereges, Jun 29, 2008
5. ### Ben BacarisseGuest

August Karlstrom <> writes:

> pereges wrote:
>> Hi, I'm trying to write a macro for the relative difference function

<snip>
> ... I would
> write something like the following:
>
> #include <assert.h>
> #include <math.h>
>
> double max(double x, double y)
> {
> return (x > y)? x: y;
> }
>
>
> double reldiff(double x, double y)
> {
> assert((x != 0) || (y != 0));

What is this assert for? What problem is caused by x == 0 && y == 0?
Did you intend to check that

assert(max(fabs(x), fabs(y)) != 0);

? If so, i would argue that this is not a good use of assert. Not
unless you know something about the use of this function that makes
calling it in that way a logic fault in the program.

> return fabs(x - y) / max(fabs(x), fabs(y));
> }

--
Ben.

Ben Bacarisse, Jun 29, 2008
6. ### August KarlstromGuest

Ben Bacarisse wrote:
> August Karlstrom <> writes:
>>
>> double reldiff(double x, double y)
>> {
>> assert((x != 0) || (y != 0));

>
> What is this assert for? What problem is caused by x == 0 && y == 0?

Division by zero (mathematically speaking).

> Did you intend to check that
>
> assert(max(fabs(x), fabs(y)) != 0);

Yes, same thing.

> ? If so, i would argue that this is not a good use of assert. Not
> unless you know something about the use of this function that makes
> calling it in that way a logic fault in the program.

The relative difference of x and y is undefined if both x and y are
zero. The assert statement is used here to put constraints on the input
parameters (for debugging purposes and for documentation). The caller
must of course make sure that this precondition is met.

August

August Karlstrom, Jun 29, 2008
7. ### Ben BacarisseGuest

August Karlstrom <> writes:

> Ben Bacarisse wrote:
>> August Karlstrom <> writes:
>>>
>>> double reldiff(double x, double y)
>>> {
>>> assert((x != 0) || (y != 0));

>>
>> What is this assert for? What problem is caused by x == 0 && y == 0?

>
> Division by zero (mathematically speaking).
>
>> Did you intend to check that
>>
>> assert(max(fabs(x), fabs(y)) != 0);

>
> Yes, same thing.

Duh! I forgot the fabs()s were there (despite having typed them).

--
Ben.

Ben Bacarisse, Jun 29, 2008
8. ### Barry SchwarzGuest

On Sun, 29 Jun 2008 07:57:08 -0700 (PDT), pereges <>
wrote:

>On Jun 29, 7:17 pm, August Karlstrom <> wrote:
>
>
>> Are you sure you really need to define the functions as macros? If you
>> define them as ordinary functions they can typically be inlined by the
>> compiler anyway. This way you will also have type safety. I would write
>> something like the following:
>>
>> #include <assert.h>
>> #include <math.h>
>>
>> double max(double x, double y)
>> {
>> return (x > y)? x: y;
>>
>> }
>>
>> double reldiff(double x, double y)
>> {
>> assert((x != 0) || (y != 0));
>>
>> return fabs(x - y) / max(fabs(x), fabs(y));
>>
>> }

>
>Is it always better to write functions over macros for even smaller
>things, say square of a number ?

It is always better to write the code in a way that best (tm)
satisfies several possibly competing requirements.

First and foremost, it must do the job.
It should be easily maintained.
It should be easy to read and understand
It should be extendable (for example, can the "arguments" be
expressions with side effects).
It should promote re-use.

>For my project, I have a file called util.h which basically contains
>some math macros like this, error display macro, constants etc. all at
>one place and its a few lines anyway so including it in most files
>won't hurt that bad whereas if i write full fledge functions it

A lot of projects are done this way so it can't be that unreasonable.

>increases the amount of code that is included everytime. Is that
>correct ?

If you invoke a macro 100 times will it generate more code than if you
call the same function 100 times? As always, it depends.

If you find a problem with the macro, how many routines will need to
be recompiled? If you fix the function, how many?

You are on the verge of treating the issue as a premature
optimization. In the vast majority of cases, this places the emphasis
on the wrong syllable. Write clear working code and don't worry about
extra lines of code in the compile phase or a few extra K of memory in
the execution phase.

Remove del for email

Barry Schwarz, Jun 29, 2008
9. ### Flash GordonGuest

August Karlstrom wrote, On 29/06/08 16:40:
> Ben Bacarisse wrote:
>> August Karlstrom <> writes:
>>>
>>> double reldiff(double x, double y)
>>> {
>>> assert((x != 0) || (y != 0));

>>
>> What is this assert for? What problem is caused by x == 0 && y == 0?

>
> Division by zero (mathematically speaking).

Logically it would more more sense to do
if (x==0 && y==0) return 0;
After all, if most numbers are identical (i.e. 0) there is no difference!

Alternatively, reduce the above to one test with:
if (x==y) return 0;

>> Did you intend to check that
>>
>> assert(max(fabs(x), fabs(y)) != 0);

>
> Yes, same thing.
>
>> ? If so, i would argue that this is not a good use of assert. Not
>> unless you know something about the use of this function that makes
>> calling it in that way a logic fault in the program.

>
> The relative difference of x and y is undefined if both x and y are
> zero. The assert statement is used here to put constraints on the input
> parameters (for debugging purposes and for documentation). The caller
> must of course make sure that this precondition is met.

Since this function is for use in determining if two numbers are
identical such a restriction would not be sensible. Return 0 which is a
sensible definition for the relative difference if both number are 0
since the absolute difference is 0!
--
Flash Gordon