Warum liefert "$ ((~ 33))" -34?

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

und mein kernel ist:

$ 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

FRAGE: Ist ~ für die Verneinung der Nummer AFAIK. Aber warum ~33produziert -34und warum ~255produziert -256?

Gasko Peter
quelle
2
Bitweise Negation, nicht zu verwechseln mit arithmetischer Negation ( -x )
chepner

Antworten:

21

Die Manpage von bash sagt:

   ! ~    logical and bitwise negation

Vorzeichenbehaftete Nummern werden normalerweise in der Zweierkomplementdarstellung gespeichert :

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

Das bedeutet, wenn Sie eine Zahl wie 2 nehmen, wird diese bitweise als 0010 interpretiert. Nach bitweiser Negation wird dies zu 1101, was der Darstellung von -3 entspricht.

michas
quelle
10

Dies ist das Ergebnis der Zweierkomplementarithmetik.

~ist eine bitweise Negation, die alle bearbeiteten Bits invertiert. Die Zweierkomplementarithmetik arbeitet, indem alle Bits invertiert und 1 addiert werden. Da Sie nur die Bits invertiert, aber nicht eins addiert haben, erhalten Sie die gleiche Zahl, invertiert, minus eins.

Wikipedia hat einen guten Artikel auf Zweier-Komplement hier .

Als Beispiel:

  • 3 in binär ist 0011
  • -3 in (Zweierkomplement) binär ist 1101
  • Invertieren 0011gibt Ihnen 1100, was -4 ist, da Sie nicht 1 hinzugefügt haben.
Chris Down
quelle
3

Der Operator ~ ist der bitweise Operator NOT. Es zu benutzen ist nicht dasselbe wie eine Zahl zu negieren.

Aus Wikipedia ist eine bitweise NOT-Operation gleich dem Zweierkomplement des Wertes minus eins:

NICHT x = −x - 1

Das Negieren einer Binärzahl entspricht der Annahme ihres Zweikomplementwerts.

Mit dem Operator ~ NOT = wird der Ein-Komplement-Wert verwendet.

Einfacher ausgedrückt, ~ kippt einfach alle Bits der Binärdarstellung .

Für Ihre Beispiele:

33 (dezimal) = 0x00100001 (8-Bit-Binär)

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

Oder in Dezimalarithmetik mit der Formel ~ x = -x - 1:

~ 33 = -33-1 = -34

und

~ 255 = -255-1 = -256

Damien
quelle
1

Das Problem ist, dass ~ ein bitweiser Operator ist. Sie negieren also mehr Bits, als Sie vielleicht beabsichtigen. Sie können dies besser sehen, indem Sie die Ergebnisse in hexadezimal konvertieren. Beispiel:

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

im Vergleich zu dem, was du hattest:

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

Ich gehe davon aus, dass Sie 0x33 negieren wollen. Wenn dies der Fall ist, würde dies funktionieren:

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

Sie müssen auch & verwenden, das der bitweise Operator ist, um das gesamte ff am Anfang zu vermeiden.

Neil McGill
quelle
1

Der ~(arithmetische) Operator kippt alle Bits , er heißt bitweiser Negationsoperator:

! ~    logical and bitwise negation

An Stellen, an denen der Kontext arithmetisch ist, wird eine Zahl mit allen Bits als Nullen in alle Bits als Einsen geändert. A $(( ~0 ))konvertiert alle Bits der Zahlendarstellung (heutzutage normalerweise 64 Bits) in alle.

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

Eine Zahl mit allen Einsen wird als negative Zahl (erstes Bit 1) 1oder einfach interpretiert -1.

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

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

Das Gleiche gilt für alle anderen Zahlen, zum Beispiel: $(( ~1 ))Alle Bits spiegeln:

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

Oder binär: 1111111111111111111111111111111111111111111111111111111111111110

Was, als Zahl in Zweierdarstellung interpretiert, ist:

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

Im Allgemeinen ist die menschliche mathematische Gleichung $(( ~n ))gleich$(( -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

Und (deine Frage):

$ n=33   ; echo "$(( ~n )) $(( -n-1 ))"
-34 -34
Isaac
quelle
0

Zuerst muss man verstehen, dass 33 eine 32-Bit- oder eine 64-Bit-Zahl ist.

Zur Vereinfachung nehme ich eine 8-Bit-Nummer (= 1 Byte)

Dezimal 33 besteht aus acht Bits: 00100001, das Umkehren der Bits ergibt 11011110.

Da das höherwertige Bit 1 ist, ist es eine negative Zahl.

Wenn Sie eine negative Zahl drucken, druckt das System ein Minuszeichen und ergänzt die negative Zahl um eine Zwei.

Das Komplement von Zwei ist: Kippen der Bits und Addieren von 1.

11011110 ==> 00100001 ==> Das Hinzufügen von 1 ==> 00100010 ergibt eine Dezimalstelle 34 hinter dem Minuszeichen.

F. Harthoorn
quelle