To pytanie dotyczące eksploracji, co oznacza, że nie jestem całkowicie pewien, o co chodzi w tym pytaniu, ale myślę, że chodzi o największą liczbę całkowitą w Bash. W każdym razie zdefiniuję to pozornie.
$ echo $((1<<8))
256
Tworzę liczbę całkowitą, przesuwając nieco. Jak daleko mogę się posunąć?
$ echo $((1<<80000))
1
Najwyraźniej nie tak daleko. (1 jest nieoczekiwany i wrócę do niego). Ale,
$ echo $((1<<1022))
4611686018427387904
jest nadal pozytywny. Jednak nie to:
$ echo $((1<<1023))
-9223372036854775808
I krok dalej,
$ echo $((1<<1024))
1
Dlaczego 1? A dlaczego następujące?
$ echo $((1<<1025))
2
$ echo $((1<<1026))
4
Czy ktoś chciałby przeanalizować tę serię?
AKTUALIZACJA
Moja maszyna:
$ 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
Gilles „SO- przestań być zły”
źródło
źródło
Odpowiedzi:
Bash używa
intmax_t
zmiennych do arytmetyki . W twoim systemie mają one długość 64 bitów, więc:który jest
binarnie (1, a następnie 62 0). Przesuń to jeszcze raz:
który jest
binarnie (63 0s), w arytmetyki dopełniacza dwóch.
Aby uzyskać największą reprezentatywną liczbę całkowitą, musisz odjąć 1:
który jest
binarnie.
Jak wskazano w ilkkachu „s odpowiedzi , przenosząc zajmuje offset modulo 64 na 64-bitowych x86 procesorów (czy używając
RCL
lubSHL
), który wyjaśnia zachowanie widzisz:jest równoważne z
$((1<<0))
. Tak więc$((1<<1025))
to$((1<<1))
,$((1<<1026))
jest$((1<<2))
...Znajdziesz definicje typów i maksymalne wartości w
stdint.h
; w twoim systemie:źródło
-
ma wyższy priorytet niż<<
.echo $((1<<63-1))
daje mi4611686018427387904
.$((1<<63-1))
jest równe$(((1<<63)-1))
.Z
CHANGES
pliku dla wersjibash
2.05b:Na maszynach x86_64
intmax_t
odpowiada 64-bitowym liczbom całkowitym ze znakiem. Otrzymujesz znaczące wartości między-2^63
i2^63-1
. Poza tym zakresem po prostu się owijasz.źródło
-2^63
i2^63-1
włącznie.Przesunięcie o 1024 daje jeden, ponieważ wielkość przesunięcia jest skutecznie brana modulo do liczby bitów (64), a więc
1024 === 64 === 0
i1025 === 65 === 1
.Przesunięcie czegoś innego niż a
1
wyjaśnia, że to nie jest mały obrót, ponieważ wyższe bity nie zawijają się do dolnego końca, zanim wartość przesunięcia wynosi (przynajmniej) 64:Możliwe, że takie zachowanie zależy od systemu. Kod bash Stephen związana pokazuje tylko zwykły przesunięcie, bez jakiejkolwiek kontroli dla wartości po prawej stronie. Jeśli dobrze pamiętam, procesory x86 używają tylko dolnych sześciu bitów wartości przesunięcia (w trybie 64-bitowym), więc zachowanie może być bezpośrednio z języka maszynowego. Ponadto myślę, że przesunięcia o więcej niż szerokość bitów również nie są jasno określone w C (
gcc
ostrzega przed tym).źródło
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
lub9223372036854775807
w grudniu.Ta liczba „+1” staje się ujemna.
To jest tak samo, jak
1<<63
:Następnie proces powtarza się ponownie.
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
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”: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
:Maksymalna liczba całkowita (
intmax
) wynika z ostatniej wartościd
.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):
sh
Przetłumaczone na prawie każdą powłokę:
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 :
wypisał błąd na wartościach
$((2^63))
, a nie ksh.źródło