1

In order to speed up the performance of my program, I'd like to introduce a function for calculating the leftover of a floating point division (where the quotient is natural, obviously).

Therefore I have following simple function:

double mfmod(double x,double y) {
  double a;
  return ((a=x/y)-(int)a)*y;
  }

As I've heard I could speed up even more by putting this function within a #define clause, but the variable a makes this quite difficult. At this moment I'm here:

#define mfmod(x,y) {         \
  double a;                  \
  return ((a=x/y)-(int)a)*y; \
  }

But trying to launch this gives problems, due to the variable.

The problems are the following: a bit further I'm trying to launch this function:

double test = mfmod(f, div);

And this can't be compiled due to the error message type name is not allowed. (for your information, f and div are doubles)

Does anybody know how to do this? (if it's even possible) (I'm working with Windows, more exactly Visual Studio, not with GCC)

Dominique
  • 16,450
  • 15
  • 56
  • 112
  • Except the sequencing issue (you don't know if the assignment will be done before the value of `a` is read for the subtraction), and that the variable `a` will not be available outside the scope of the block, and that it will return from whatever function it is in (which might not be a problem), your macro looks okay. You have to give us something more than "gives problems". Please [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask) and learn how to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve). – Some programmer dude Feb 21 '17 at 15:59
  • note that `x` & `y` could be expressions and you'd have to copy them as well to avoid side-effects. – Jean-François Fabre Feb 21 '17 at 15:59
  • 2
    @Someprogrammerdude no it has a `return` – Jean-François Fabre Feb 21 '17 at 16:00
  • 7
    what about making the function inline instead of a macro? – Chris Turner Feb 21 '17 at 16:00
  • 1
    @Dominique A macro is not an inline function. Imagine this as text search and replace. Thus, the return affects the place where the macro is invoked. Probably not your intention. – Scheff's Cat Feb 21 '17 at 16:00
  • @Jean-FrançoisFabre Well it *might* be okay, but in this case it probably won't do what the OP expected. – Some programmer dude Feb 21 '17 at 16:02
  • Also, don't do premature optimizations! First of all make good, clean, readable and maintainable code. Then measure, profile and benchmark a compiler-optimized build. Then, if and only if there are problems with "performance" should you try to hand-optimize your code, in the *right* places (as indicated by profiling). And don't worry about doing e.g. `x/y` twice, any good compiler will detect it and do it only once, reusing the result. – Some programmer dude Feb 21 '17 at 16:05
  • @ChrisTurner inline is a "suggestion" to the compiler: it can get rid of it for optimization porposes – LPs Feb 21 '17 at 16:06
  • 4
    Use the standard `fmod` function. – n. m. could be an AI Feb 21 '17 at 16:07
  • 3
    Possible duplicate of [Can a C macro contain temporary variables?](http://stackoverflow.com/questions/8764733/can-a-c-macro-contain-temporary-variables) – BnBDim Feb 21 '17 at 16:08
  • @LPs so either way you end up with an optimized call to that function :) – Chris Turner Feb 21 '17 at 16:08
  • 1
    Also (repeating myself just to push the point) in both the function and the macro you have a sequencing problem. When you do `a=x/y - (int)a` you don't know if the assignment to `a` will be done before the value of `a` is read for the casting and subtraction. You could be doing the subtraction with the uninitialized value of `a`, which is indeterminate (and a possible trap condition leading to *undefined behavior*). Why don't you do e.g. `double a = x/y; return a - (int) a;`? – Some programmer dude Feb 21 '17 at 16:13
  • it can be done; and using the preprocessor to boot: `#include ` – sp2danny Feb 21 '17 at 16:17

3 Answers3

2

As I've heard I could speed up even more by putting this function within a #define clause

I think you must have misunderstood. Surely the advice was to implement the behavior as a (#defined) macro, instead of as a function. Your macro is syntactically valid, but the code resulting from expanding it is not a suitable replacement for calling your function.

Defining this as a macro is basically a way to manually inline the function body, but it has some drawbacks. In particular, in standard C, a macro that must expand to an expression (i.e. one that can be used as a value) cannot contain a code block, and therefore cannot contain variable declarations. That, in turn, may make it impossible to avoid multiple evaluation of the macro arguments, which is a big problem.

Here's one way you could write your macro:

#define mfmod(x,y) ( ((x)/(y)) - (int) ((x)/(y)) )

This is not a clear a win over the function, however, as its behavior varies with the argument types, it must evaluate both arguments twice (which can produce unexpected and even undefined results in some cases), and it must also perform the division twice.

If you were willing to change the usage mode so that the macro sets a result variable instead of expanding to an expression, then you could get around many of the problems. @BnBDim provided a first cut at this, but it suffers from some of the same type and multiple-evaluation problems as the above. Here's how you could do it to obtain the same result as your function:

#define mfmod(x, y, res) do {           \
    double _div  = (y);                 \
    double _quot = (double) (x) / _div; \
    res = (_quot - (int) _quot) * _div; \
} while (0)

Note that it takes care to reference the arguments once each, and also inside parentheses but for res, which must be an lvalue. You would use it much like a void function instead of like a value-returning function:

double test;
mfmod(f, div, test);

That still affords a minor, but unavoidable risk of breakage in the event that one of the actual arguments to the macro collides with one of the variables declared inside the code block it provides. Using variable names prefixed with underscores is intended to minimize that risk.


Overall, I'd be inclined to go with the function instead, and to let the compiler handle the inlining. If you want to encourage the compiler to do so then you could consider declaring the function inline, but very likely it will not need such a hint, and it is not obligated to honor one.

Or better, just use fmod() until and unless you determine that doing so constitutes a bottleneck.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • why the `do/while(0)` instead of simple curly braces? – Jean-François Fabre Feb 21 '17 at 16:45
  • 1
    @Jean-FrançoisFabre because then you don't get a warning about an empty statement when you follow an invocation of the macro with a semicolon (`mfmod(1.5, .6, result);`), and in fact the semicolon is required. This is very conventional for statement-like macros. – John Bollinger Feb 21 '17 at 16:56
1

To answer the stated question: yes, you can declare variables in defined macro 'functions' like the one you are working with, in certain situations. Some of the other answers have shown examples of how to do this.

The problem with your current #define is that you are telling it to return something in the middle of your code, and you are not making a macro that expands in the way you probably want. If I use your macro like this:

...
double y = 1.0;
double x = 1.0;
double z = mfmod(x, y);
int other = (int)z - 1;
...

This is going to expand to:

...
double y = 1.0;
double x = 1.0;
double z = {
  double a;
  return ((a=x/y)-(int)a)*y;
};
int other = (int)z - 1;
...

The function (if it compiled) would never proceed beyond the initialization of z, because it would return in the middle of the macro. You also are trying to 'assign' a block of code to z.

That being said, this is another example of making assumptions about performance without any (stated) benchmarking. Have you actually measured any performance problem with just using an inline function?

__attribute__((const))
extern inline double mfmod(const double x, const double y) {
  const double a = x/y;
  return (a - (int)a) * y;
}

Not only is this cleaner, clearer, and easier to debug than the macro, it has the added benefit of being declared with the const attribute, which will suggest to the compiler that subsequent calls to the function with the same arguments should return the same value, which can cause repeated calls to the function to be optimized away entirely, whereas the macro would be evaluated every time (conceptually). To be honest, even using the local double to cache the division result is probably a premature optimization, since the compiler will probably optimize this away. If this were me, and I absolutely HAD to have a macro to do this, I would write it as follows:

#define mfmod(x, y) (((x/y)-((int)(x/y)))*y)

There will almost certainly not be any noticeable performance hit under optimization for doing the division twice. If there were, I would use the inline function above. I will leave it to you to do the benchmarking.

Ideasthete
  • 1,553
  • 13
  • 22
  • @Dominique - again, it doesn't sound like you've benchmarked this. You said "the performance is equal to the normal inline functions". The performance of an inlined function is more or less identical to the performance of a macro substitution. The entire point of inlining is that it avoids function call overhead. It feels like you are trying to optimize for a problem you don't have. Benchmark my inline function (without the attribute) against any macro and see how it does. Macros are rarely the right answer to solve performance issues, and they almost certainly are not the answer here. – Ideasthete Feb 23 '17 at 19:38
0

You could use this work-around

#define mfmod(x,y,res)       \
  do {                       \
      double a=(x)/(y);      \
      res = (a-(int)a)*(y);  \
  } while(0)
sp2danny
  • 7,488
  • 3
  • 31
  • 53
BnBDim
  • 136
  • 5
  • cache `y` so it's not evaluated twice (side effect issue), otherwise could work. – Jean-François Fabre Feb 21 '17 at 16:44
  • @Jean-FrançoisFabre `y` is never going to be evaluated twice. This is C. `y` is a numeric value. Caching it will be optimized out because it would just waste more stack space with an extra value to store the same value that the parameter stored. If it isn't optimized out, it will make the program worse. – Ideasthete Feb 23 '17 at 19:41
  • `mfmod(x,sqrt(y),res)`: you'll see `sqrt(y)` is evaluated twice because there's a function call. That's what I meant. – Jean-François Fabre Feb 23 '17 at 19:50
  • The function that was being translated into a macro had arguments which were doubles. I was operating under the assumption that the macro was being used to replace that function, in which case if the arguments were still doubles caching `y` would not make a difference... but you are correct that with a macro if the parameters are not doubles the behavior will be different. But at that point, there is no guarantee that the macro works anyway. If we are going to broaden the scope to 'it takes any argument', then what happens in the above if someone passes in a function that returns void as `y`? – Ideasthete Feb 25 '17 at 06:46