produire un entier en décalant un peu. Jusqu'où puis-je aller?
Jusqu'à ce que la représentation entière s'enroule (la valeur par défaut dans la plupart des shells).
Un entier 64 bits enveloppe généralement at 2**63 - 1
.
C'est 0x7fffffffffffffff
ou 9223372036854775807
en décembre.
Ce nombre «+1» devient négatif.
C'est la même chose que 1<<63
:
$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1
Après cela, le processus se répète.
$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))
Le résultat dépend mod 64
de la valeur de décalage [a] .
[a] Extrait de: Intel® 64 et IA-32 Architectures Software Developer's Manual: Volume 2 Le nombre est masqué à 5 bits (ou 6 bits si en mode 64 bits et REX.W est utilisé). La plage de comptage est limitée à 0 à 31 (ou 63 si le mode 64 bits et REX.W est utilisé). .
Aussi: rappelez-vous que $((1<<0))
c'est1
$ 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
Donc, tout dépend de la façon dont le nombre est proche d'un multiple de 64.
Tester la limite:
La manière robuste de tester quel est l'entier positif (et négatif) maximum est de tester chaque bit à tour de rôle. Ses moins de 64 étapes pour la plupart des ordinateurs de toute façon, ce ne sera pas trop lent.
frapper
Tout d'abord, nous avons besoin du plus grand entier du formulaire 2^n
(ensemble de 1 bit suivi de zéros). Nous pouvons le faire en décalant vers la gauche jusqu'à ce que le décalage suivant rend le nombre négatif, également appelé «bouclage»:
a=1; while ((a>0)); do ((b=a,a<<=1)) ; done
Où b
est le résultat: la valeur avant le dernier quart de travail qui échoue à la boucle.
Ensuite, nous devons essayer chaque bit pour savoir lesquels affectent le signe de e
:
c=$b;d=$b;
while ((c>>=1)); do
((e=d+c))
(( e>0 )) && ((d=e))
done;
intmax=$d
Le nombre entier maximum ( intmax
) résulte de la dernière valeur de d
.
Du côté négatif (moins que 0
), nous répétons tous les tests mais testons quand un bit peut être mis à 0 sans s'enrouler.
Voici un test complet avec impression de toutes les étapes (pour 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
Traduit dans presque n'importe quel 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"
En exécutant ce qui précède pour de nombreux shells,
tous (sauf bash 2.04 et mksh) ont accepté des valeurs allant jusqu'à ( 2**63 -1
) sur cet ordinateur.
Il est intéressant de signaler que la coquille att :
$ attsh --version
version sh (AT&T Research) 93u+ 2012-08-01
imprimé une erreur sur les valeurs de $((2^63))
, pas ksh cependant.