Erzeugen einer ganzen Zahl durch Verschieben eines Bits. Wie weit kann ich gehen?
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
oder 9223372036854775807
im Dezember.
Diese Zahl '+1' wird negativ.
Das ist das Gleiche wie 1<<63
:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Danach wiederholt sich der Vorgang erneut.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
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
$ for i in 80000 1022 1023 1024 1025 1026; do echo "$((i%64)) $((1<<i))"; done
0 1
62 4611686018427387904
63 -9223372036854775808
0 1
1 2
2 4
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:
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
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
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
Die maximale Ganzzahl ( intmax
) ergibt sich aus dem letzten Wert von d
.
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):
#!/bin/bash
sayit(){ printf '%020d 0x%016x\n' "$1"{,}; }
a=1; while ((a>0)) ; do((b=a,a<<=1)) ; sayit "$a"; done
c=$b;d=$b; while((c>>=1)); do((e=d+c));((e>0))&&((d=e)) ; sayit "$d"; done;
intmax=$d
a=-1; while ((a<0)) ; do((b=a,a<<=1)) ; sayit "$b"; done;
c=$b;d=$b; while ((c<-1)); do((c>>=1,e=d+c));((e<0))&&((d=e)); sayit "$d"; done
intmin=$d
printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"
Sch
In fast jede Shell übersetzt:
#!/bin/sh
printing=false
sayit(){ "$printing" && printf '%020d 0x%016x\n' "$1" "$1"; }
a=1; while [ "$a" -gt 0 ];do b=$a;a=$((a<<1)); sayit "$a"; done
c=$b;d=$b; while c=$((c>>1)); [ "$c" -gt 0 ];do e=$((d+c)); [ "$e" -gt 0 ] && d=$e ; sayit "$d"; done;
intmax=$d
a=-1; while [ "$a" -lt 0 ];do b=$a;a=$((a<<1)); sayit "$b"; done;
c=$b;d=$b; while [ "$c" -lt -1 ];do c=$((c>>1));e=$((d+c));[ "$e" -lt 0 ] && d=$e ; sayit "$d"; done
intmin=$d
printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"
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 :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
druckte einen Fehler auf Werte von $((2^63))
, aber nicht ksh.