「$((〜33))」が-34を生成するのはなぜですか?


12
$ echo $(( 255 ))
255
$ echo $(( 33 ))
33
$ echo $(( ~33 ))
-34
$ echo $(( ~255 ))
-256
$ 

私のカーネルは:

$ 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

質問: ~数字を無視するためです。しかし、なぜない~33生産-34となぜ~255農産物は-256


2
ビット
ごとの

回答:


21

bashのmanページには次のように書かれています:

   ! ~    logical and bitwise negation

通常、符号付きの数値は2の補数表現で保存されます。

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

これは、2のような数を取る場合、ビット単位で0010として解釈されることを意味します。ビット単位の否定の後、これは1101になり、-3を表します。


10

これは、2の補数演算の結果です。

~演算対象のすべてのビットを反転させるビットごとの否定です。2の補数演算は、すべてのビットを反転し、1を加算することで機能します。ビットを反転しただけで、1を追加していないため、同じ数、反転、マイナス1が得られます。

ウィキペディアには、2の補数に関する優れた記事があります

例として:

  • バイナリの3は 0011
  • -3 in(2の補数)バイナリは 1101
  • 反転は0011あなたを与える1100あなたは1を追加していないので、-4です。

3

〜演算子はビット単位のNOT演算子です。これを使用することは、数値を否定することとは異なります。

ウィキペディア、ビット単位のNOT演算は、値マイナス1の2の補数をとることに等しいです。

NOT x = −x − 1

2進数を否定することは、その2の補数の値を取ることと同等です。

〜NOT演算子=を使用して、その補数の値を取ります。

簡単に言えば、〜はバイナリ表現のすべてのビットを反転させるだけです。

あなたの例:

33(10進数)= 0x00100001(8ビットバイナリ)

〜33 =〜0x00100001 = 0x11011110 = -34(10進数)

または、10進算術では、〜x = -x-1式を使用します。

〜33 = -33-1 = -34

そして

〜255 = -255-1 = -256


1

問題は〜がビット単位の演算子であることです。したがって、おそらくあなたが意図するよりも多くのビットを否定しています。結果を16進数に変換することで、これをよりよく見ることができます。

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

対あなたが持っていたもの:

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

私はあなたが0x33を否定することを意味すると仮定しています。その場合、これは機能します:

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

また、&を使用して、ビット単位のand演算子を使用して、開始時のすべてのffを回避する必要があります。


1

~(算術)オペレータは、すべてのビットを反転させ、それがビット単位の否定演算子と呼ばれます:

! ~    logical and bitwise negation

したがって、コンテキストが算術である場所では、すべてのビットをゼロとして、すべてのビットを1として数値を変更します。A $(( ~0 ))は、数値表現のすべてのビット(今日では通常64ビット)をすべて1に変換します。

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

すべて1の数は、負の数(最初のビット11または単にとして解釈され-1ます。

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

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

同じことが他のすべての数値にも起こり$(( ~1 ))ます。たとえば、すべてのビットを反転します。

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

または、バイナリで: 1111111111111111111111111111111111111111111111111111111111111110

これは、2の表現の数値として解釈されます:

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

一般的に、人間の数学方程式は、である$(( ~n ))に等しいです。$(( -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

0

最初に、33は32ビットまたは64ビットの数値であることを理解する必要があります。

便宜上、8ビット数(= 1バイト)を取ります

10進数33は8ビットです:00100001、ビットを反転すると11011110になります。

高位ビットは1であるため、負の数です。

負の数を出力すると、システムはマイナス記号を出力し、負の数で2の補数を実行します。

2の補数は、ビットを反転して1を追加します。

11011110 ==> 00100001 ==> 1を追加すると==> 00100010マイナス記号の後ろに10進数の34が表示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.