Effect of a Bitwise Operator on a Boolean in Java

Effect of a Bitwise Operator on a Boolean in Java

The operators &, ^, and | are bitwise operators when the operands are primitive integral types. They are logical operators when the operands are boolean, and their behaviour in the latter case is specified. See the section 15.22.2 of the Java Language Specification for details.

Why are bitwise operators slower at comparing booleans than the normal ones in Java?

Louis Wasserman's comment is the correct diagnosis. The number of calls to the random number generator strongly affects the performance, so short-circuiting is important. I modified the program to count the numbers of calls using a couple of methods like this:

private static boolean normalCountedRandom() {
normalCount++;
return rng.nextBoolean();
}

I also did multiple measurements in each run to eliminate any issue of start-up effects. A typical output was:

Bitwise operator: 1985
Normal operator: 1560
Bitwise operator: 1967
Normal operator: 1547
Bitwise operator: 2046
Normal operator: 1557
Bitwise operator: 2009
Normal operator: 1553
Bitwise Random calls: 800006428
Normal Random calls: 600030931

The 4:3 ratio is as expected. Each if does one compulsory call. If using a short circuit operator, only half of those will result in a second call, for an expected 1.5 calls per if, compared to 2 per if without the short-circuit. This ratio is similar to the performance ratio, assuming the calls account for most, but not all, of the time.

The short-circuit behavior is documented in the JLS. Technically, when applied to boolean operands, & and | are Boolean Logical Operators. The "normal" operators are Conditional-And and Conditional-Or Operators.

It is generally better to avoid having the number of iterations depend on a Random result, although in this case, with enough iterations, the variance between runs is small.

Are the &, |, ^ bitwise operators or logical operators?

The Java operators &, | and ^ are EITHER bitwise operators OR logical operators ... depending on the types of the operands. If the operands are integers, the operators are bitwise. If they are booleans, then the operators are logical.

And this is not just me saying this. The JLS describes these operators this way too; see JLS 15.22.

(This is just like + meaning EITHER addition OR string concatenation ... depending on the types of the operands. Or just like a "rose" meaning either a flower or a shower attachment. Or "cat" meaning either a furry animal or a UNIX command. Words mean different things in different contexts. And this is true for the symbols used in programming languages too.)


There are already logical operators &&, ||, why use &, |, ^?

In the case of the first two, it is because the operators have different semantics with regards to when / whether the operands get evaluated. The two different semantics are needed in different situations; e.g.

    boolean res = str != null && str.isEmpty();

versus

    boolean res = foo() & bar();  // ... if I >>need<< to call both methods.

The ^ operator has no short-circuit equivalent because it simply doesn't make sense to have one.

Java boolean |= operator

From the JLS:

15.26.2. Compound Assignment Operators

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

15.22.2. Boolean Logical Operators &, ^, and |

When both operands of a &, ^, or | operator are of type boolean or Boolean, then the type of the bitwise operator expression is boolean. In all cases, the operands are subject to unboxing conversion (§5.1.8) as necessary.

For |, the result value is false if both operand values are false; otherwise, the result is true.

This means that

val |= somethingElse();

is strictly equivalent to

val = val | somethingElse();

(assuming somethingElse() returns boolean or Boolean).

I'd be curious if right operand is evaluated if left value already is true.

Yes, it would be evaluated, since | does not short-circuit:

15.7.2. Evaluate Operands before Operation

The Java programming language guarantees that every operand of an operator (except the conditional operators &&, ||, and ? :) appears to be fully evaluated before any part of the operation itself is performed.

15.24. Conditional-Or Operator ||

Thus, || computes the same result as | on boolean or Boolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

Why do we usually use || over |? What is the difference?

If you use the || and && forms, rather than the | and & forms of these operators, Java will not bother to evaluate the right-hand operand alone.

It's a matter of if you want to short-circuit the evaluation or not -- most of the time you want to.

A good way to illustrate the benefits of short-circuiting would be to consider the following example.

Boolean b = true;
if(b || foo.timeConsumingCall())
{
//we entered without calling timeConsumingCall()
}

Another benefit, as Jeremy and Peter mentioned, for short-circuiting is the null reference check:

if(string != null && string.isEmpty())
{
//we check for string being null before calling isEmpty()
}

more info

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;
}
}

is there any other use of & other than bitwise AND

& can be applied on two boolean operands as a non short circuiting version of binary AND operator (unlike the short circuiting && operator).

| can be applied on two boolean operands as a non short circuiting version of binary OR operator (unlike the short circuiting || operator).

^ (XOR) can also be applied on two boolean operands.

To summarize, all 3 operators can serve as boolean operators (when applied to boolean operands) or bit-wise operators (when applies to integer operands).

These operators are described in JLS 15.22.2.:

15.22.2. Boolean Logical Operators &, ^, and |

When both operands of a &, ^, or | operator are of type boolean or Boolean, then the type of the bitwise operator expression is boolean. In all cases, the operands are subject to unboxing conversion (§5.1.8) as necessary.

  • For &, the result value is true if both operand values are true; otherwise, the result is false.

  • For ^, the result value is true if the operand values are different; otherwise, the result is false.

  • For |, the result value is false if both operand values are false; otherwise, the result is true.

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.



Related Topics



Leave a reply



Submit