Boolean Operators VS Bitwise Operators

Boolean operators vs Bitwise operators

Here are a couple of guidelines:

  • Boolean operators are usually used on boolean values but bitwise operators are usually used on integer values.
  • Boolean operators are short-circuiting but bitwise operators are not short-circuiting.

The short-circuiting behaviour is useful in expressions like this:

if x is not None and x.foo == 42:
# ...

This would not work correctly with the bitwise & operator because both sides would always be evaluated, giving AttributeError: 'NoneType' object has no attribute 'foo'. When you use the boolean andoperator the second expression is not evaluated when the first is False. Similarly or does not evaluate the second argument if the first is True.

Python bitwise vs boolean operators

Bitwise operators are usually the very wrong tool for the job. Bitwise operators are not faster (they have to do more work actually), and have a different precedence, so are bound to different parts of a larger expression compared to boolean operators.

However, in some specific frameworks, bitwise operators replace boolean operators because they can be hooked into. There are __or__ and __and__ specal methods that let you control the return value for | and &, but there are no such hooks for the boolean operators (as the latter short-circuit; evaluating both expressions to pass to a hook would defeat that).

So if the article is talking about numpy (or numpy-derived frameworks such as Pandas or Scipy), or an ORM framework like SQLAlchemy, Peewee or Django, then there is a good reason to use bitwise operators.

Boolean bitwise and logical operators

As noted in the comments, you should use logical operators when you're doing logic and bitwise operators when doing bitwise operations.

One of the main differences among these is that C++ will short-circuit the logical operations; meaning that it will stop evaluating the operands as soon as it's clear what the result of the operation is.

As an example, this code:

bool foo() {
std::puts("foo");
return true;
}

bool bar() {
std::puts("bar");
return true;
}

//...

auto const res = foo() || bar();

will only output:

foo

Function bar won't be evaluated as, in this case, evaluating foo is enough to know the result of expression foo() || bar() is true.

Why use logical operators when bitwise operators do the same?

The most common use of short-circuit evaluations using logical operators isn't performance but avoiding errors. See this :

if (a && a.length)

You can't simply use & here.

Note that using & instead of && can't be done when you don't deal with booleans. For example & on 2 (01 in binary) and 4 (10 in binary) is 0.

Note also that, apart in if tests, && (just like ||) is also used because it returns one of the operands :

"a" & "b" => 0
"a" && "b" => "b"

More generally, using & in place of && is often possible. Just like omitting most ; in your javascript code. But it will force you to think more than necessary (or will bring you weird bugs from time to time).

Logical vs bitwise

Logical operators operate on logical values, while bitwise operators operate on integer bits. Stop thinking about performance, and use them for they're meant for.

if x and y: # logical operation
...
z = z & 0xFF # bitwise operation

and' (boolean) vs '&' (bitwise) - Why difference in behavior with lists vs numpy arrays?

and tests whether both expressions are logically True while & (when used with True/False values) tests if both are True.

In Python, empty built-in objects are typically treated as logically False while non-empty built-ins are logically True. This facilitates the common use case where you want to do something if a list is empty and something else if the list is not. Note that this means that the list [False] is logically True:

>>> if [False]:
... print 'True'
...
True

So in Example 1, the first list is non-empty and therefore logically True, so the truth value of the and is the same as that of the second list. (In our case, the second list is non-empty and therefore logically True, but identifying that would require an unnecessary step of calculation.)

For example 2, lists cannot meaningfully be combined in a bitwise fashion because they can contain arbitrary unlike elements. Things that can be combined bitwise include: Trues and Falses, integers.

NumPy objects, by contrast, support vectorized calculations. That is, they let you perform the same operations on multiple pieces of data.

Example 3 fails because NumPy arrays (of length > 1) have no truth value as this prevents vector-based logic confusion.

Example 4 is simply a vectorized bit and operation.

Bottom Line

  • If you are not dealing with arrays and are not performing math manipulations of integers, you probably want and.

  • If you have vectors of truth values that you wish to combine, use numpy with &.

Differences in boolean operators: & vs && and | vs ||

Those are the bitwise AND and bitwise OR operators.

int a = 6; // 110
int b = 4; // 100

// Bitwise AND

int c = a & b;
// 110
// & 100
// -----
// 100

// Bitwise OR

int d = a | b;
// 110
// | 100
// -----
// 110

System.out.println(c); // 4
System.out.println(d); // 6

Thanks to Carlos for pointing out the appropriate section in the Java Language Spec (15.22.1, 15.22.2) regarding the different behaviors of the operator based on its inputs.

Indeed when both inputs are boolean, the operators are considered the Boolean Logical Operators and behave similar to the Conditional-And (&&) and Conditional-Or (||) operators except for the fact that they don't short-circuit so while the following is safe:

if((a != null) && (a.something == 3)){
}

This is not:

if((a != null) & (a.something == 3)){
}

"Short-circuiting" means the operator does not necessarily examine all conditions. In the above examples, && will examine the second condition only when a is not null (otherwise the whole statement will return false, and it would be moot to examine following conditions anyway), so the statement of a.something will not raise an exception, or is considered "safe."

The & operator always examines every condition in the clause, so in the examples above, a.something may be evaluated when a is in fact a null value, raising an exception.

Is there a difference between using a logical operator or a bitwise operator in an if block in Java?

The logical operator works on booleans, and the bitwise operator works on bits. In this case, the effect is going to be the same, but there are two differences:

  1. The bitwise operator is not meant for that, which makes it harder to read but most importantly
  2. The logical OR operator will evaluate the first condition. If it's true, it does not matter what the next condition results in, the result will be true, so the second clause is not executed

Here's some handy code to prove this:

public class OperatorTest {

public static void main(String[] args){
System.out.println("Logical Operator:");
if(sayAndReturn(true, "first") || sayAndReturn(true, "second")){
//doNothing
}

System.out.println("Bitwise Operator:");
if(sayAndReturn(true, "first") | sayAndReturn(true, "second")){
//doNothing
}
}

public static boolean sayAndReturn(boolean ret, String msg){
System.out.println(msg);
return ret;
}
}


Related Topics



Leave a reply



Submit