# Why does "\$(( ~33 ))" produce -34?

``````\$ echo \$(( 255 ))
255
\$ echo \$(( 33 ))
33
\$ echo \$(( ~33 ))
-34
\$ echo \$(( ~255 ))
-256
\$
``````

and my kernel is:

``````\$ uname -a
Linux HOSTNAME 3.2.0-40-generic-pae #64-Ubuntu SMP Mon Mar 25 21:44:41 UTC 2013 i686 i686 i386 GNU/Linux
``````

QUESTION: `~` is for negating the number AFAIK. But why does `~33` produce `-34` and why does `~255` produce `-256`?

• Bitwise negation, not to be confused with arithmetic negation (-x) May 10, 2013 at 19:31

The man page of bash says:

``````   ! ~    logical and bitwise negation
``````

Signed numbers are usually stored in Two's complement representation:

``````...
-4 = 1100
-3 = 1101
-2 = 1110
-1 = 1111
0 = 0000
1 = 0001
2 = 0010
3 = 0011
...
``````

This means if you take a number like 2 it is bitwise interpreted as 0010. After bitwise negation this becomes 1101, which is the representation of -3.

This is the result of two's complement arithmetic.

`~` is a bitwise negation that inverts all of the bits being operated upon. Two's complement arithmetic works by inverting all of the bits and adding 1. Since you have only flipped the bits, but not added one, you get the same number, inverted, minus one.

Wikipedia has a good article on two's complement here.

As an example:

• 3 in binary is `0011`
• -3 in (two's complement) binary is `1101`
• Inverting `0011` gives you `1100`, which is -4, since you haven't added 1.

The ~ operator is the bitwise NOT operator. Using it is not the same as negating a number.

From wikipedia, a bitwise NOT operation is equal to taking the two's complement of the value minus one:

NOT x = −x − 1

Negating a binary number is equivalent to taking its two-complement value.

Using the ~ NOT operator = take its one-complement value.

In simpler terms, ~ just flips all the bits of the binary representation.

33 (decimal) = 0x00100001 (8-bit binary)

~33 = ~0x00100001 = 0x11011110 = -34 (decimal)

Or in decimal arithmetics, using the ~x = -x - 1 formula:

~33 = -33 - 1 = -34

and

~255 = -255 - 1 = -256

The `~` (arithmetic) operator flips all bits, it is called the bitwise negation operator:

``````! ~    logical and bitwise negation
``````

So, in places where the context is arithmetic, it changes a number with all bits as zeros to all bits as ones. A `\$(( ~0 ))` converts all the bits of the number representation (usually 64 bits nowadays) to all ones.

``````\$ printf '%x\n' "\$(( ~0 ))"
ffffffffffffffff
``````

A number with all ones is interpreted as the negative number (first bit `1`) `1`, or simply `-1`.

``````\$ printf '%x\n' "-1"
ffffffffffffffff

\$ echo "\$(( ~0 ))"
-1
``````

The same happens to all other numbers, for example: `\$(( ~1 ))` flips all bits:

``````\$ printf '%x\n' "\$(( ~1 ))"
fffffffffffffffe
``````

Or, in binary: `1111111111111111111111111111111111111111111111111111111111111110`

Which, interpreted as a number in two's representation is:

``````\$ echo "\$(( ~1 ))"
-2
``````

In general, the human math equation is that `\$(( ~n ))` is equal to `\$(( -n-1 ))`

``````\$ n=0    ; echo "\$(( ~n )) \$(( -n-1 ))"
-1 -1

\$ n=1    ; echo "\$(( ~n )) \$(( -n-1 ))"
-2 -2

\$ n=255  ; echo "\$(( ~n )) \$(( -n-1 ))"
-256 -256
``````

``````\$ n=33   ; echo "\$(( ~n )) \$(( -n-1 ))"
-34 -34
``````

The problem is that ~ is a bit-wise operator. Hence you are negating more bits than you perhaps intend. You can see this better by converting the results to hex e.g.:

``````result_in_hex=\$(printf "%x" \$(( ~33 ))); echo \$result_in_hex
ffffffffffffffde
``````

``````result_in_dec=\$(printf "%d" \$(( ~33 ))); echo \$result_in_dec
-34
``````

I'm assuming you mean to negate 0x33. If that is the case then this would work:

``````result_in_hex=\$(printf "%2x" \$(( ( ~ 0x33 ) & 0xFF))); echo \$result_in_hex
cc
``````

You need to also use & which is the bit-wise and operator to avoid all the ff at the start.

First you have to understand that 33 is a 32 bits or a 64 bits number.

For conveniance I take an eight bit number (= 1 byte)

decimal 33 is in eight bits: 00100001, flipping the bits results in 11011110.

Because the high order bit is 1, it is a negative number.

Printing a negative number, the system prints a minus sign and then does a two's complement on the negative number.

Two's complement is: flipping the bits and adding 1.

11011110 ==> 00100001 ==> adding 1 ==> 00100010 results in decimal 34 behind the minus sign.