$ 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?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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.
Method 2
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
0011gives you1100, which is -4, since you haven’t added 1.
Method 3
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.
For your examples:
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
Method 4
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 '%xn' "$(( ~0 ))" ffffffffffffffff
A number with all ones is interpreted as the negative number (first bit 1) 1, or simply -1.
$ printf '%xn' "-1" ffffffffffffffff $ echo "$(( ~0 ))" -1
The same happens to all other numbers, for example: $(( ~1 )) flips all bits:
$ printf '%xn' "$(( ~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
And (your question):
$ n=33 ; echo "$(( ~n )) $(( -n-1 ))" -34 -34
Method 5
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
versus what you had:
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.
Method 6
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.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0