0

I would like to know if there is any difference in speed or performance in C++ between:

AND operation: &&, and, bitand

OR operation: ||, or, bitor

Or it's the same performance for all of them?

Tobias Ribizel
  • 5,331
  • 1
  • 18
  • 33
Mircea
  • 31
  • 1
  • 9
  • 5
    `&&` and `and` are aliases. `bitand` is an alias of `&`. And there is no difference between e.g. `&&` and `and`. None whatsoever. – Some programmer dude Jan 06 '18 at 15:49
  • 6
    Here you go: http://en.cppreference.com/w/cpp/language/operator_alternative Regarding performance: you need to measure it under your expected workload. – Richard Critten Jan 06 '18 at 15:50
  • 4
    What would be the reason to know the difference in performance of operators that do different things? – juanchopanza Jan 06 '18 at 15:51
  • 1
    also && represents rvalue references too in c++11 – Albin Paul Jan 06 '18 at 15:58
  • 2
    The use of `and`, `or`, etc is uncommon and therefore slightly confusing for many readers of the code. So it is recommended to use `&&` and `||`, unless you have an unusual keyboard where these are missing. – Bo Persson Jan 06 '18 at 15:59
  • They do unrelated things. And if you're asking about speed, this kind of question is a bit like asking "How could I lose more weight, by getting a haircut or by trimming my fingernails?" – Mike Dunlavey Jan 06 '18 at 17:27
  • I'm voting to close this question as off-topic because unless one is measuring specific use cases, the answer could be anything at all (an operation is faster or slower depending on how it is used). – halfer Jan 06 '18 at 17:58

2 Answers2

4

Before going into details, && and and are equivalent, so are & and bitand, || and or as well as | and bitor. More details can be found on cppreference.com

There definitely are differences between them, so let's look at them in more detail:

  • && and || are logical operators. Their result is either true or false, nothing else.
    If at least one of the operands (||) or both operands (&&) is not false, then the result is true, false otherwise.

  • & and | are bitwise operators. They operate on every bit of the operands independently.
    This is mostly used for bit-twiddling operations on numbers like to set all but the lowermost 3 bits of a number to 0 (think about their binary representation):

    int result1 = number & 0b111;
    // or to set the 3 lowermost bits to 1
    int result2 = number | 0b111;
    

You might know that for conditional statements, every number in C++ can be interpreted as a boolean value, more specifically 0 is false and everything else is true. This can lead to some confusion, as the following example shows:

int a = 1;
int b = 2;
if (a && b) {
    std::cout << "a && b\n";
}
if (a & b) {
    std::cout << "a & b\n";
}

This will output only a && b because a & b is 0 and thus false, even though a and b both are not false.

In short, use && and || for logical operations, & and | for bitwise operations on numbers, but watch out for side-effects:

Apart from the different scopes of use, there is another difference between these operators, namely the mandatory short-circuit evaluation for logical operators (&& and ||). This means that if we already know the result of the expression from evaluating the first operand, then the second operand must not be evaluated. This means that the following two pieces of code are equivalent:

    bool result = is_this_true() && is_that_true();
    // equivalent:
    bool result;
    if (is_this_true()) {
        result = is_that_true();
    } else {
        result = false;
    }

The same holds for the logical or operator:

    bool result = is_this_true() || is_that_true();
    // equivalent:
    bool result;
    if (is_this_true()) {
        result = true;
    } else {
        result = is_that_true();
    }

This is because

  1. If one of the operands of && is false, then the result is always false
  2. If one of the operands of || is true, then the result is always true

This can definitely have an impact on the performance compared to the bitwise operators, basically in two different ways:

  1. If the evaluation of is_that_true() takes a lot of time, then the short-circuit evaluation might save you time in the cases when the result gets short-circuited.

  2. If the evaluation of both is_this_true() and is_that_true() are quite fast but have side-effects the compiler cannot get rid of, then the additional branch introduced by the equivalent if statement might have a small performance penalty involved (for more details, read up on branch misprediction). However, in most cases this performance difference is so tiny that you should never worry about it unless the evaluation of these logical operators is your performance bottleneck (which, again, should be very unlikely)

If you want to know more, there are already several answers detailing the effect of short circuit evaluation, see for example Is short-circuiting logical operators mandated? And evaluation order?

Tobias Ribizel
  • 5,331
  • 1
  • 18
  • 33
  • Branch misprediction has a catastrophic effect. It can imply the loss of dozen cycles. Where performance truly matters (in innermost loops), branchless expressions can be advantageous. –  Jan 06 '18 at 16:12
  • I know, but I find it very unlikely that a logical operation is a) the bottleneck of an application and b) the second operand can be evaluated very quickly, but at the same time has a side-effect that prevents the compiler from using a branchless instruction instead of a branch. The question itself didn't seem to me to ask for too much technicality ;) – Tobias Ribizel Jan 06 '18 at 16:19
1

Or it's the same performance for all of them?

This is a bit of an apples/oranges question. and and bitand perform different jobs.

example:

bool both_nonzero(int x, int y)
{
    return x and y;
}

bool have_corresponding_bits(int x, int y)
{
    return bool(x bitand y);
}

corresponding assembler (gcc-x86_64 -O3):

both_nonzero(int, int):
        test    edi, edi
        setne   al
        test    esi, esi
        setne   dl
        and     eax, edx
        ret

have_corresponding_bits(int, int):
        test    edi, esi
        setne   al
        ret

As you can see, the second function requires fewer instructions, but from a CPU's point of view it's doing a simpler task (bitwise operations being the bread and butter of a CPU's life's work).

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142