producendo un numero intero spostando un po '. Quanto lontano posso andare?
Fino a quando la rappresentazione dei numeri interi non si avvolge (impostazione predefinita nella maggior parte delle shell).
Un numero intero a 64 bit si avvolge solitamente a 2**63 - 1
.
Questo è 0x7fffffffffffffff
o9223372036854775807
in dicembre.
Quel numero "+1" diventa negativo.
È lo stesso 1<<63
, quindi:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Successivamente il processo si ripete di nuovo.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
Il risultato dipende dal mod 64
valore di spostamento [a] .
[a] Da: Manuale dello sviluppatore del software per architetture Intel® 64 e IA-32: Volume 2 Il conteggio è mascherato su 5 bit (o 6 bit se in modalità 64 bit e viene utilizzato REX.W). L'intervallo di conteggio è limitato da 0 a 31 (o 63 se si utilizzano la modalità 64-bit e REX.W). .
Inoltre: ricorda che lo $((1<<0))
è1
$ 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
Quindi, tutto dipende da quanto è vicino il numero a un multiplo di 64.
Test del limite:
Il modo affidabile per verificare qual è il numero intero massimo positivo (e negativo) è testare a turno ciascuno di essi. Sono comunque meno di 64 passaggi per la maggior parte dei computer, non sarà troppo lento.
bash
Innanzitutto è necessario il numero intero più grande del modulo 2^n
(set di 1 bit seguito da zeri). Possiamo farlo spostando a sinistra fino a quando il turno successivo rende il numero negativo, chiamato anche "a capo":
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
Dov'è b
il risultato: il valore prima dell'ultimo spostamento che fallisce il ciclo.
Quindi dobbiamo provare ogni bit per scoprire quali influenzano il segno di e
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
Il numero intero massimo ( intmax
) risulta dall'ultimo valore di d
.
Sul lato negativo (minore di 0
) ripetiamo tutti i test ma testiamo quando un po 'potrebbe essere fatto 0 senza avvolgerci.
Un intero test con la stampa di tutti i passaggi è questo (per 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
Tradotto in quasi ogni shell:
#!/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"
Eseguendo quanto sopra per molte shell,
tutti (tranne bash 2.04 e mksh) hanno accettato valori fino a ( 2**63 -1
) in questo computer.
È interessante segnalare che l'att shell :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
ha stampato un errore sui valori di $((2^63))
, non su ksh.