“$ ((~ 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

질문 : ~ 숫자 AFAIK를 무시하기위한 것입니다. 그러나 왜 ~33생산 -34하고 왜 ~255생산 -256합니까?


2
비트 부정, 산술 부정 ( -x ) 과 혼동하지 말 것
chepner

답변:


21

bash의 맨 페이지는 다음과 같이 말합니다.

   ! ~    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을 뺍니다.

Wikipedia에는 ​​2의 보완에 대한 좋은 기사가 있습니다 .

예로서:

  • 이진수로 3은 0011
  • -2에서 2의 2 진수는 1101
  • 반전 001111001을 추가하지 않았기 때문에 -4입니다.

3

~ 연산자는 비트 NOT 연산자입니다. 그것을 사용하는 것은 숫자를 부정하는 것과 다릅니다.

에서 위키 피 디아 , 비트 단위 NOT 연산은 값을 뺀 2의 보수를 복용 같다 :

NOT x = −x − 1

이진수를 음수로 바꾸는 것은 2 보수 값을 취하는 것과 같습니다.

~ NOT 연산자를 사용하면 1의 보수 값을 가져옵니다.

간단히 말해서, ~는 이진 표현의 모든 비트를 뒤집습니다 .

예를 들어 :

33 (10 진수) = 0x00100001 (8 비트 이진)

~ 33 = ~ 0x00100001 = 0x11011110 = -34 (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

또한 시작시 모든 ff를 피하려면 비트 및 연산자 인 &를 사용해야합니다.


1

~(연산) 운영자는 모든 비트를 플립 그것이 비트 부정 조작이라고 :

! ~    logical and bitwise negation

따라서 문맥이 산술적 인 곳에서는 모든 비트가 0 인 숫자를 모든 비트가 1 인 숫자로 변경합니다. A $(( ~0 ))는 숫자 표현의 모든 비트 (일반적으로 오늘날 64 비트)를 모든 비트로 변환합니다.

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

모든 숫자가있는 숫자는 음수 (첫 번째 비트 1) 1또는 간단히 해석됩니다 -1.

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

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

다른 모든 숫자에서도 마찬가지입니다. 예를 들면 다음과 같습니다. $(( ~1 ))모든 비트를 뒤집습니다.

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

또는 이진으로 : 1111111111111111111111111111111111111111111111111111111111111110

두 표현에서 숫자로 해석되는 것은 다음과 같습니다.

$ 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 비트 0000001이며 비트를 뒤집 으면 11011110이됩니다.

상위 비트는 1이므로 음수입니다.

음수를 인쇄하면 시스템은 빼기 부호를 인쇄 한 다음 음수에 2의 보수를 수행합니다.

2의 보완은 비트를 뒤집고 1을 더하는 것입니다.

11011110 ==> 00100001 ==> 1 ==> 00100010을 추가하면 빼기 부호 뒤에 10 진수 34가 생깁니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.