J'ai un programme simple:
public class Mathz {
static int i = 1;
public static void main(String[] args) {
while (true){
i = i + i;
System.out.println(i);
}
}
}
Quand je lance ce programme, tout ce que je vois est 0
pour i
ma sortie. Je me serais attendu à ce que la première fois, nous l'aurions i = 1 + 1
, suivie de i = 2 + 2
, suivie de i = 4 + 4
etc.
Est-ce dû au fait que dès que nous essayons de re-déclarer i
sur le côté gauche, sa valeur est réinitialisée 0
?
Si quelqu'un pouvait m'indiquer les détails les plus fins, ce serait formidable.
Changez le int
en long
et il semble imprimer les nombres comme prévu. Je suis surpris de la vitesse à laquelle il atteint la valeur maximale de 32 bits!
la source
0
sur les premières itérations, mais la vitesse de sortie est obscurcir ce fait de l'OP). Pourquoi est-ce accepté?introduction
Le problème est un débordement d'entier. S'il déborde, il revient à la valeur minimale et continue à partir de là. S'il sous-déborde, il revient à la valeur maximale et continue à partir de là. L'image ci-dessous est celle d'un odomètre. J'utilise cela pour expliquer les débordements. C'est un débordement mécanique mais un bon exemple quand même.
Dans un odomètre, le
max digit = 9
, allant au-delà du maximum signifie9 + 1
, ce qui reporte et donne un0
; Cependant, il n'y a pas de chiffre supérieur à changer en a1
, donc le compteur se réinitialise àzero
. Vous voyez l'idée - les "débordements d'entiers" viennent à l'esprit maintenant.Ainsi,
2147483647 + 1
déborde et s'enroule autour de-2147483648
. Par conséquentint i=2147483647 + 1
serait débordé, ce qui n'est pas égal à2147483648
. De plus, vous dites "il imprime toujours 0". Ce n'est pas le cas, car http://ideone.com/WHrQIW . Ci-dessous, ces 8 chiffres montrent le point auquel il pivote et déborde. Il commence alors à imprimer des 0. Aussi, ne soyez pas surpris de la vitesse de calcul, les machines d'aujourd'hui sont rapides.Pourquoi le débordement d'entier "s'enroule"
PDF original
la source
Non, il n'imprime pas que des zéros.
Changez-le en ceci et vous verrez ce qui se passe.
Ce qui se passe est appelé débordement.
la source
true
pari<10000
:)while(k --> 0)
familièrement nommé "whilek
va à0
";)production:
la source
Comme je n'ai pas assez de réputation, je ne peux pas publier l'image de la sortie pour le même programme en C avec une sortie contrôlée, vous pouvez essayer vous-même et voir qu'il imprime réellement 32 fois, puis comme expliqué en raison d'un débordement i = 1073741824 + 1073741824 changements à -2147483648 et un autre ajout supplémentaire est hors de portée de int et devient Zero.
la source
system("deltree C:")
, puisque vous êtes sous DOS / Windows). Le débordement d'entier signé est un comportement non défini en C / C ++, contrairement à Java. Soyez très prudent lorsque vous utilisez ce type de construction.signed and unsigned
entiers sans aucun comportement indéfinii += i
de 32 itérations, puis l'a faitif (i > 0)
. Le compilateur pourrait optimiser celaif(true)
car si nous ajoutons toujours des nombres positifs, ilsi
seront toujours supérieurs à 0. Il pourrait également laisser la condition dans, où elle ne sera pas exécutée, à cause du débordement représenté ici. Étant donné que le compilateur peut produire deux programmes également valides à partir de ce code, son comportement n'est pas défini.La valeur de
i
est stockée en mémoire à l'aide d'une quantité fixe de chiffres binaires. Lorsqu'un numéro nécessite plus de chiffres que ce qui est disponible, seuls les chiffres les plus bas sont stockés (les chiffres les plus élevés sont perdus).S'ajouter
i
à lui-même équivaut à multiplieri
par deux. Tout comme la multiplication d'un nombre par dix en notation décimale peut être effectuée en faisant glisser chaque chiffre vers la gauche et en mettant un zéro à droite, la multiplication d'un nombre par deux en notation binaire peut être effectuée de la même manière. Cela ajoute un chiffre à droite, donc un chiffre se perd à gauche.Ici, la valeur de départ est 1, donc si nous utilisons 8 chiffres pour stocker
i
(par exemple),00000001
00000010
00000100
et ainsi de suite, jusqu'à l'étape finale non nulle
10000000
00000000
Peu importe le nombre de chiffres binaires alloués pour stocker le numéro, et quelle que soit la valeur de départ, tous les chiffres seront finalement perdus lorsqu'ils seront poussés vers la gauche. Après ce point, continuer à doubler le nombre ne changera pas le nombre - il sera toujours représenté par tous les zéros.
la source
C'est correct, mais après 31 itérations, 1073741824 + 1073741824 ne calcule pas correctement et après cela n'imprime que 0.
Vous pouvez refactoriser pour utiliser BigInteger, ainsi votre boucle infinie fonctionnera correctement.
la source
int
.long
peut représenter des nombres plus grands queint
possible.Pour déboguer de tels cas, il est bon de réduire le nombre d'itérations dans la boucle. Utilisez ceci au lieu de votre
while(true)
:Vous pouvez alors voir qu'il commence par 2 et double la valeur jusqu'à ce qu'il provoque un débordement.
la source
J'utiliserai un nombre de 8 bits pour l'illustration car il peut être complètement détaillé dans un court espace. Les nombres hexadécimaux commencent par 0x, tandis que les nombres binaires commencent par 0b.
La valeur maximale pour un entier non signé de 8 bits est 255 (0xFF ou 0b11111111). Si vous ajoutez 1, vous vous attendez généralement à obtenir: 256 (0x100 ou 0b100000000). Mais comme c'est trop de bits (9), c'est au-dessus du maximum, donc la première partie est simplement supprimée, vous laissant effectivement 0 (0x (1) 00 ou 0b (1) 00000000, mais avec le 1 supprimé).
Ainsi, lorsque votre programme s'exécute, vous obtenez:
la source
Le plus grand littéral décimal de type
int
est 2147483648 (= 2 31 ). Tous les littéraux décimaux de 0 à 2147483647 peuvent apparaître partout où un littéral int peut apparaître, mais le littéral 2147483648 peut apparaître uniquement comme l'opérande de l'opérateur de négation unaire -.Si une addition entière déborde, alors le résultat est les bits de poids faible de la somme mathématique comme représenté dans un format de complément à deux suffisamment grand. En cas de dépassement de capacité, alors le signe du résultat n'est pas le même que le signe de la somme mathématique des deux valeurs d'opérande.
la source