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?
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?
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
&&
is false
, then the result is always false
||
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:
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.
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?
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).