produzindo um número inteiro deslocando um pouco. Até onde posso ir?
Até que a representação inteira envolva (o padrão na maioria dos shells).
Um número inteiro de 64 bits geralmente envolve em 2**63 - 1
.
Isso é 0x7fffffffffffffff
ou 9223372036854775807
em dezembro.
Esse número '+1' se torna negativo.
É o mesmo que 1<<63
, assim:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Depois disso, o processo se repete novamente.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
O resultado depende mod 64
do valor de mudança [a] .
[a] De: Manual do desenvolvedor de software das arquiteturas Intel® 64 e IA-32: Volume 2 A contagem é mascarada em 5 bits (ou 6 bits se estiver no modo de 64 bits e REX.W estiver sendo usado). O intervalo de contagem é limitado de 0 a 31 (ou 63 se o modo de 64 bits e o REX.W forem usados). .
Lembre-se também de que $((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
Portanto, tudo depende da proximidade do número de um múltiplo de 64.
Testando o limite:
A maneira robusta de testar qual é o número máximo positivo (e negativo) máximo é testar cada um por vez. Seus menos de 64 passos para a maioria dos computadores, de qualquer maneira, não será muito lento.
bater
Primeiro, precisamos do maior número inteiro do formulário 2^n
(conjunto de 1 bit seguido por zeros). Podemos fazer isso deslocando a esquerda até o próximo turno tornar o número negativo, também chamado de "contornar":
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
Onde b
está o resultado: o valor antes do último turno que falha no loop.
Então, precisamos tentar todos os detalhes para descobrir quais afetam o sinal de e
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
O número inteiro máximo ( intmax
) resulta do último valor de d
.
No lado negativo (menos que 0
), repetimos todos os testes, mas testamos quando um pouco pode ser feito 0 sem envolver.
Um teste completo com a impressão de todas as etapas é este (para o 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
Traduzido para quase qualquer 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"
Executando o descrito acima para muitos shells,
todos (exceto o bash 2.04 e o mksh) aceitaram valores de até ( 2**63 -1
) neste computador.
É interessante relatar que o shell att :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
imprimiu um erro nos valores de $((2^63))
, mas não no ksh.