1

Not sure which is better (faster) about these two way:

// first
#define BOUNDED(x,lo,hi) ((x) < (lo) ? (lo) : (x) > (hi) ? (hi) : (x))

// second
double Bounded(double x, double lo, double hi) {
    return fmax(fmin(x, hi), lo);
};    

In both I'll use them with double. Does it depends by the compiler?

markzzz
  • 47,390
  • 120
  • 299
  • 507
  • In the second one, you have a total of 3 function-calls. If they are not all inlined, then it will probably be slower than the first one. – barak manos Nov 07 '16 at 10:53
  • 6
    Measure it and find out. – Lightness Races in Orbit Nov 07 '16 at 10:54
  • 4
    How about this: Focus on writing correct and maintainable code and choosing the right data structures and algorithms and let the compiler optimize things. Then, if you need more performance still, use a profiler and chip away at the identified hotspots and forget this business about macros vs functions and which one is faster. – Nik Bougalis Nov 07 '16 at 11:13
  • 2
    @NikBougalis: Absolutely. I'd rather pay for a 10% increase in my compute farm than have all these macros flying around. – Bathsheba Nov 07 '16 at 11:15

4 Answers4

10

The rule of thumb in C++ is to avoid macros whenever possible.

For example, your macro will suffer from repeated evaluation of arguments if I pass something like BOUNDED(x++, low++, hi++).

If you want to retain the generic nature of the macro, then why not write

template<typename Y>
inline Y Bounded(Y x, Y lo, Y hi)
{
    return x < lo ? lo : x > hi ? hi : x;
}

I can't see this being slower than the macro approach. Note that the compiler may ignore inline as it sees fit. Profile the performance to be sure. You could consider passing const Y& x etc. for large types, but this will probably wind up slower for the Y = double case.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    I'm not the down-voter, but the question asks which one is **faster**, not which one is more suitable for the conventions of the C++ language. – barak manos Nov 07 '16 at 10:54
  • @barakmanos: Yes I just noticed I didn't really answer that. Have done so now. – Bathsheba Nov 07 '16 at 10:56
  • Don't you think that the function-call has any runtime impact? (unless inlined, and even so, if I remember correctly, it is just a recommendation for the compiler, so there's no guarantee to avoid the function-call). – barak manos Nov 07 '16 at 10:58
  • 2
    @barakmanos, Compilers are quite good at figuring out when to inline and when not to. On average they produce better running code than the "optimizing" developer who thinks they know when to inline. – StoryTeller - Unslander Monica Nov 07 '16 at 11:00
  • @barakmanos: Yes, adding `inline` is probably wise, although these days compilers tend to be better than their advisors, if you get my meaning. – Bathsheba Nov 07 '16 at 11:00
  • 1
    @Bathsheba, but not required. All function templates are implicitly `inline`. – StoryTeller - Unslander Monica Nov 07 '16 at 11:01
  • See http://stackoverflow.com/questions/10535667/does-it-make-any-sense-to-use-inline-keyword-with-templates – Bathsheba Nov 07 '16 at 11:01
  • @Bathsheba, explicit instantiation notwithstanding, there is no point in marking a template as inline. A good lecture on the subject from this years cppcon https://www.youtube.com/watch?v=vwrXHznaYLA – StoryTeller - Unslander Monica Nov 07 '16 at 11:03
  • @StoryTeller: I'd go one step further and dare suggest there's no point in making *any* function `inline`. – Bathsheba Nov 07 '16 at 11:04
  • 3
    @Bathsheba, you'd be wrong :) See the lecture. the `inline` keyword has a very specific meaning as a linker directive. A regular function in a header (not a template) will produce a "multiple definition" error, unless it is marked with the `inline` keyword. Of course, one can ask *why* have a function definition in a header, but that's an entirely different matter. :) – StoryTeller - Unslander Monica Nov 07 '16 at 11:06
  • 1
    @StoryTeller: Yes that was a silly thing to say. I'll leave it up since my removing it will invalidate your helpful comment. – Bathsheba Nov 07 '16 at 11:12
  • If they're always of `double` type, then I believe `long_running_function()` instead of `low++` would be closer to a possible use case to illustrate the problem with the macro. – Angew is no longer proud of SO Nov 07 '16 at 11:46
4

If I were you, I would choose function and made it templatized constexpr:

template<typename T>
constexpr T Bounded(T x, T lo, T hi)
{
    return x < lo ? lo : x > hi ? hi : x;
}

That way you have generic approach (as with macro) but with two advantages:

  1. You can use concepts (once they enter standard :) ) to constrain types passed into template.
  2. It will be evaluated at compile time if you pass constexpr arguments.

As for your exact question:

Modern compilers are good at optimizing. Very good in fact. I suspect that because of those optimizations both versions will take similar time to execute. But without profiling on your build configuration it's just wild guess.

Lehu
  • 761
  • 4
  • 14
2

I'll add this for completeness. Once c++17 comes along, you can just use std::clamp

template<class T>
constexpr const T& clamp( const T& v, const T& lo, const T& hi );
template<class T, class Compare>
constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp );
  1. If v compares less than hi, returns the larger of v and lo, otherwise returns the smaller of v and hi. Uses operator< to compare the values.
  2. Same as (1), but uses comp to compare the values.
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
0

I suppose, that you should to trust c++ compiler and use function instead macro, because it can perform some optimizations like inlining (which will do all necessary work for you). Moreover, usage of macro in c++ is bad practise, which can lead to errors

Alex Aparin
  • 4,393
  • 5
  • 25
  • 51