generując liczbę całkowitą przez nieznaczne przesunięcie. Jak daleko mogę się posunąć?
Dopóki nie zapełni się reprezentacja liczb całkowitych (domyślna w większości powłok).
64-bitowa liczba całkowita zwykle otacza 2**63 - 1
.
To 0x7fffffffffffffff
lub 9223372036854775807
w grudniu.
Ta liczba „+1” staje się ujemna.
To jest tak samo, jak 1<<63
:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Następnie proces powtarza się ponownie.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
Wynik zależy mod 64
od wartości przesunięcia [a] .
[a] From: Intel® 64 and IA-32 Architectures Software Developer's Manual: Tom 2 Liczba jest maskowana do 5 bitów (lub 6 bitów, jeśli jest w trybie 64-bitowym i używany jest REX.W). Zakres zliczania jest ograniczony od 0 do 31 (lub 63, jeśli używany jest tryb 64-bitowy i REX.W). .
Pamiętaj też, że $((1<<0))
tak1
$ 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
Wszystko zależy więc od tego, jak blisko jest liczba do wielokrotności 64.
Testowanie limitu:
Solidnym sposobem na sprawdzenie, która jest maksymalną dodatnią (i ujemną) liczbą całkowitą, jest przetestowanie każdego bitu po kolei. W każdym razie jest to mniej niż 64 kroki dla większości komputerów, nie będzie to zbyt wolne.
grzmotnąć
Najpierw potrzebujemy największej liczby całkowitej w formularzu 2^n
(zestaw 1 bitów, po których następują zera). Możemy to zrobić, przesuwając w lewo, aż następna zmiana spowoduje, że liczba będzie ujemna, zwana również „zawijaniem”:
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
Gdzie b
jest wynik: wartość przed ostatnim przesunięciem, które zawiedzie pętlę.
Następnie musimy co najmniej starać się dowiedzieć, które z nich wpływają na znak e
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
Maksymalna liczba całkowita ( intmax
) wynika z ostatniej wartości d
.
Z drugiej strony (mniej niż 0
) powtarzamy wszystkie testy, ale testujemy, kiedy bit można zrobić 0 bez zawijania.
Cały test z wydrukowaniem wszystkich kroków jest następujący (dla 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"
sh
Przetłumaczone na prawie każdą powłokę:
#!/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"
Uruchamiając powyższe dla wielu powłok,
wszystkie (oprócz bash 2.04 i mksh) zaakceptowały wartości do ( 2**63 -1
) na tym komputerze.
Interesujące jest zgłoszenie, że powłoka att :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
wypisał błąd na wartościach $((2^63))
, a nie ksh.