Dies ist eine Erkundungsfrage, was bedeutet, dass ich nicht ganz sicher bin, worum es bei dieser Frage geht, aber ich denke, es geht um die größte Ganzzahl in Bash. Wie auch immer, ich werde es scheinbar definieren.
$ echo $((1<<8))
256
Ich produziere eine ganze Zahl, indem ich ein bisschen verschiebe. Wie weit kann ich gehen?
$ echo $((1<<80000))
1
Offenbar nicht so weit. (1 ist unerwartet, und ich werde darauf zurückkommen.) Aber,
$ echo $((1<<1022))
4611686018427387904
ist immer noch positiv. Nicht dies jedoch:
$ echo $((1<<1023))
-9223372036854775808
Und noch einen Schritt weiter,
$ echo $((1<<1024))
1
Warum 1? Und warum das Folgende?
$ echo $((1<<1025))
2
$ echo $((1<<1026))
4
Möchte jemand diese Serie analysieren?
AKTUALISIEREN
Meine Maschine:
$ uname -a
Linux tomas-Latitude-E4200 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
bash
arithmetic
Tomasz
quelle
quelle
Antworten:
Bash verwendet
intmax_t
Variablen für die Arithmetik . Auf Ihrem System sind diese 64 Bit lang, also:welches ist
binär (1 gefolgt von 62 0s). Verschiebe das nochmal:
welches ist
in binärer (63 0s), in Zweierkomplementarithmetik.
Um die größte darstellbare Ganzzahl zu erhalten, müssen Sie 1 subtrahieren:
welches ist
in binär.
Wie in der Antwort von ilkkachu ausgeführt , wird für das Verschieben das Offsetmodul 64 auf 64-Bit- x86- CPUs (unabhängig davon, ob verwendet oder ) verwendet. Dies erklärt das Verhalten, das Sie sehen:
RCL
SHL
ist äquivalent zu
$((1<<0))
. Also$((1<<1025))
ist$((1<<1))
,$((1<<1026))
ist$((1<<2))
...Die Typdefinitionen und Maximalwerte finden Sie in
stdint.h
; auf Ihrem System:quelle
-
hat höhere Priorität als<<
.echo $((1<<63-1))
gibt mir4611686018427387904
.$((1<<63-1))
gleich ist$(((1<<63)-1))
.Aus der
CHANGES
Datei fürbash
2.05b:Auf x86_64-Computern
intmax_t
entspricht dies vorzeichenbehafteten 64-Bit-Ganzzahlen. So erhalten Sie aussagekräftige Werte zwischen-2^63
und2^63-1
. Außerhalb dieses Bereichs erhalten Sie nur Umwicklungen.quelle
-2^63
und2^63-1
, inklusive.Eine Verschiebung um 1024 ergibt eine Eins, da der Verschiebungsbetrag effektiv modulo der Anzahl von Bits (64) genommen wird, also
1024 === 64 === 0
und1025 === 65 === 1
.Wenn Sie etwas anderes als a verschieben,
1
wird deutlich, dass es sich nicht um eine Bit-Rotation handelt, da die höheren Bits nicht auf das untere Ende umlaufen, bevor der Verschiebungswert (mindestens) 64 beträgt:Es kann sein, dass dieses Verhalten vom System abhängt. Der Bash-Code, mit dem Stephen verknüpft ist, zeigt nur eine einfache Verschiebung, ohne den Wert für die rechte Hand zu überprüfen. Wenn ich mich richtig erinnere, verwenden x86-Prozessoren nur die unteren sechs Bits des Verschiebungswerts (im 64-Bit-Modus), sodass das Verhalten möglicherweise direkt von der Maschinensprache abhängt. Außerdem glaube ich, dass Verschiebungen um mehr als die Bitbreite auch in C nicht klar definiert sind (
gcc
warnt davor).quelle
Bis sich die Ganzzahldarstellung ändert (die Standardeinstellung in den meisten Shells).
Eine 64-Bit-Ganzzahl wird normalerweise um umbrochen
2**63 - 1
.Das ist
0x7fffffffffffffff
oder9223372036854775807
im Dezember.Diese Zahl '+1' wird negativ.
Das ist das Gleiche wie
1<<63
:Danach wiederholt sich der Vorgang erneut.
Das Ergebnis ist abhängig
mod 64
vom Verschiebewert [a] .[a] Aus: Intel® 64- und IA-32-Architekturen Software-Entwicklerhandbuch: Band 2 Die Anzahl wird auf 5 Bit maskiert (oder 6 Bit, wenn im 64-Bit-Modus REX.W verwendet wird). Der Zählbereich ist auf 0 bis 31 begrenzt (oder 63, wenn der 64-Bit-Modus und REX.W verwendet werden). .
Also: denk dran das
$((1<<0))
ist1
Es kommt also darauf an, wie nahe die Zahl einem Vielfachen von 64 kommt.
Testen des Limits:
Der robuste Weg zu testen, welcher die maximale positive (und negative) Ganzzahl ist, besteht darin, jedes einzelne Bit der Reihe nach zu testen. Es sind sowieso weniger als 64 Schritte für die meisten Computer, es wird nicht zu langsam sein.
bash
Zuerst benötigen wir die größte Ganzzahl der Form
2^n
(1 Bit gefolgt von Nullen). Wir können das tun, indem wir nach links schieben, bis die nächste Schicht die Zahl negativ macht, auch "Wrap Around" genannt:Wo
b
ist das Ergebnis: Der Wert vor der letzten Schicht, die die Schleife nicht besteht.Dann müssen wir jedes Bit ausprobieren, um herauszufinden, welche das Vorzeichen von
e
:Die maximale Ganzzahl (
intmax
) ergibt sich aus dem letzten Wert vond
.Auf der negativen Seite (kleiner als
0
) wiederholen wir alle Tests, aber testen, wann ein Bit auf 0 gesetzt werden kann, ohne es umzukrempeln.Ein ganzer Test mit Ausdruck aller Schritte ist (für Bash):
Sch
In fast jede Shell übersetzt:
Wenn Sie die obigen
Anweisungen für viele Shells ausführen , haben alle (außer bash 2.04 und mksh) Werte bis (
2**63 -1
) in diesem Computer akzeptiert .Es ist interessant zu berichten, dass die att-Shell :
druckte einen Fehler auf Werte von
$((2^63))
, aber nicht ksh.quelle