# How does the bitwise complement operator (~ tilde) work?

Why is it that ~2 is equal to -3? How does `~` operator work?

15

Remember that negative numbers are stored as the two's complement of the positive counterpart. As an example, here's the representation of -2 in two's complement: (8 bits)

``````1111 1110
``````

The way you get this is by taking the binary representation of a number, taking its complement (inverting all the bits) and adding one. Two starts as 0000 0010, and by inverting the bits we get 1111 1101. Adding one gets us the result above. The first bit is the sign bit, implying a negative.

So let's take a look at how we get ~2 = -3:

Here's two again:

``````0000 0010
``````

Simply flip all the bits and we get:

``````1111 1101
``````

Well, what's -3 look like in two's complement? Start with positive 3: 0000 0011, flip all the bits to 1111 1100, and add one to become negative value (-3), 1111 1101.

So if you simply invert the bits in 2, you get the two's complement representation of -3.

## The complement operator (~) JUST FLIPS BITS. It is up to the machine to interpret these bits.

Tuesday, June 1, 2021

25
``````c = 33 + ~n;
``````

This calculates how many high order bits are remaining after using `n` low order bits.

``````((x << c)>>c
``````

This fills the high order bits with the same value as the sign bit of `x`.

``````!(blah ^ x)
``````

This is equivalent to

``````blah == x
``````
Thursday, July 29, 2021

77

This looks like swapping a value using XOR. Though I am not sure about the strings in PHP (normally you use it for ints or something). For a truth table of XOR you can look here.

The interesting thing about `XOR` is that it is reversable: A XOR B XOR B == A ... that is not working with `AND` or `OR`. Because of this fact, it can be used as in your example to swap two values:

``````\$x ^= \$y;
\$y ^= \$x;
\$x ^= \$y;
``````

means:

``````\$x = \$x ^ \$y
\$y = \$y ^ (\$x ^ \$y)                // = \$x
\$x = (\$x ^ \$y) ^ (\$y ^ (\$x ^ \$y))  // = \$y
``````
Wednesday, August 11, 2021

37

Unary (such as `~`) and binary operators in Java subject their operands to "unary numeric promotion" (JLS, Section 5.6.1) and "binary numeric promotion" (JLS, Section 5.6.2), respectively, fancy terms for "promote things to at least `int` first".

Specifically, for unary numeric promotion, quoting the JLS section linked above:

Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type:

and

... if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).

(Binary numeric promotion is similar, operating on both operands.)

So, even if `b` is a `byte`, `~b` is an `int`, because `b`'s value was promoted to an `int` first.

The solution: cast it back to a `byte`:

``````b = (byte) (~b);
``````

Why, Java?

That leaves the question, why? It seems for the operators I can find, the JVM bytecode instructions for operating on `byte`s, `short`s, and `char`s simply do not exist. For example, the unary bitwise complement operator you're using (~) is implemented as an "XOR" operation with `-1` (all bits set). From that link:

``````tempSpock &= ~mask;
``````

becomes

``````25 iload_2 // Push local variable 2 (mask).
26 iconst_m1 // Push -1.
27 ixor // Bitwise EXCLUSIVE-OR top two ints: ~mask
``````

However, I can only find instructions for XOR (and for other unary and binary operators too) for `int`s and `long`s (`float` and `double` version exist for other operators where appropriate).

So, Java must perform those promotions because there are no bytecode instructions for performing those operations on `byte`s, `short`s, or `char`s.

Why not, JVM?

That brings up another question: Why doesn't the JVM support such bytecode instructions? The answer appears to be, "Because there would be too many to encode them all in a one-byte instruction set." According to the JVM Specification, Section 2.11.1,

Given the Java Virtual Machine's one-byte opcode size, encoding types into opcodes places pressure on the design of its instruction set. If each typed instruction supported all of the Java Virtual Machine's run-time data types, there would be more instructions than could be represented in a byte. Instead, the instruction set of the Java Virtual Machine provides a reduced level of type support for certain operations. In other words, the instruction set is intentionally not orthogonal. Separate instructions can be used to convert between unsupported and supported data types as necessary.

(emphasis mine)

In conclusion, the JVM's one-bytecode instruction set precludes the bytecode instructions for most operations on `byte`s, `char`s, and `short`s, necessitating unary numeric promotion and binary numeric promotion.

Monday, August 23, 2021

87

In C++ a boolean expression produces one of two values - `0` or `1`. When you apply the unary minus `-` to the result, you get `0` or `-1`. When you re-interpret `-1` as `uchar`, you get `255`.

You can convert this expression to Java with a conditional:

``````dst[x] = (kHit >= kForeground) ? 255 : 0;
``````

Because of branching, it is not going to be as fast as the original one. There's little you can do about the speed of it, however, as Java lacks abilities to re-interpret boolean values as numerics.

Tuesday, August 24, 2021