mr.engineer
mr.engineer

Reputation: 197

Comparison operators in C++

I've got two questions regarding comparison operators in C++:

  1. When looping, which of two ways is more efficient (type of mdata and mfirst_free is double*, too):

for (double *p = mdata; p < mfirst_free; ++p) { .. }

for (double *p = mdata; p != mfirst_free; ++p) { .. }

I'll guess in the advance the same answer is valid for all primitive types - int, double, and pointers. Right?
I know < version is safer because if I somehow start with bigger pointer than expected it won't be infinite loop. But, when I'm sure I won't get invalid input, which version is more efficient?

  1. When overriding comparison operators in my own classes, are there some combinations that are the most efficient, and is there minimal required (or recommended) combination for deducing the rest?

Let's take hypothetical situation of trying to save every processor cycle - what are the best choices? Are there some that are others more elegant?

Upvotes: 0

Views: 182

Answers (4)

Olaf Dietsche
Olaf Dietsche

Reputation: 74018

As always, see for yourself and look at the generated code. With g++ 4.8 on Ubuntu 14.04, you get

    movq    -16(%rbp), %rax
    movq    %rax, -32(%rbp)
    jmp .L2
.L3:
    addq    $8, -32(%rbp)
.L2:
    movq    -32(%rbp), %rax
    cmpq    -8(%rbp), %rax
    jb  .L3

    movq    -16(%rbp), %rax
    movq    %rax, -24(%rbp)
    jmp .L4
.L5:
    addq    $8, -24(%rbp)
.L4:
    movq    -24(%rbp), %rax
    cmpq    -8(%rbp), %rax
    jne .L5

As you can see, the only relevant difference is jb .L3 vs jne .L5.

So, I would say both are equivalent from a performance point of view.


Answering the second question, the minimum necessary for comparison is operator<. You can deduce everything else from this, e.g.

bool operator==(const T &x, const T &y) {
    return !(x < y) && !(y < x);
}

bool operator!=(const T &x, const T &y) {
    return !(x == y);
}

bool operator>(const T &x, const T &y) {
    return y < x;
}

bool operator<=(const T &x, const T &y) {
    return !(y < x);
}

bool operator>=(const T &x, const T &y) {
    return !(x < y);
}

Of course, this is only true if you have the usual comparison semantics.

Upvotes: 5

tmlen
tmlen

Reputation: 9092

If the counter variable is an integer or pointer, there is probably no difference in efficiency. The effect is the same as long as the variable is just being incremented (by one) and start out smaller or equal and the end value.

But C++ iterators don't necessarily implement operator<. In fact only RandomAccessIterator are required to do so (see http://en.cppreference.com/w/cpp/iterator). So C++11 translates for(auto&& v : values) to for(auto it = std::begin(values); it != std::end(values); ++it). For example std::forward_list only has ForwardIterators and so operator< can't be used to iterate through it.

If you use OpenMP for parallelization operator< is needed:

#pragma omp parallel for
for(auto it = std::begin(values); it < std::end(values); ++it)

Because it needs to split the loop into smaller loops.

I guess in general it would be best to use operator!= to be compatible with all iterator types, unless you do something else than iterate (increment by more than one, etc.), use floating point values as counter, or use OpenMP.

Upvotes: 1

Xaphanius
Xaphanius

Reputation: 619

As far as I know, it really doesn't make a difference. I believe that

p != mfirst_free

would be translated to something in assembly similar to

   loop        
               CMP   p mfirst_free
               BEQ   exit
              {...body...}
               B     loop
   exit

while the

p < mfirst_free

would translate to the same, but instead of a BEQ instruction it would be a BGE. Same number of instructions take would take the same amount of time to be executed.

-There are various ways to translate a for loop to assembly, but my point here is that every comparison operator that you use would lead to the same running time, as far as I know.-

Upvotes: 1

Richard Hodges
Richard Hodges

Reputation: 69854

First of all, in pure c++ terms there is no correct answer to your question since the standard does not specify it and it's left to the compiler and CPU's discretion.

In real terms you're asking whether a 'branch if not equal' instruction takes any less time than a 'branch if less' instruction. In all CPUs I have ever encountered the answer will be 'no' - provided you don't get wrong-footed by incorrect branch prediction.

Upvotes: 2

Related Questions