10
votes

Pourquoi est-ce vrai?

Ceci est IEEE 754 Question standard. Je ne comprends pas complètement la mécanique derrière elle.

public class Gray {  
    public static void main(String[] args){
        System.out.println( (float) (2000000000) == (float) (2000000000 + 50));
    }
}


1 commentaires

Au fait, ce "problème" n'est pas limité à Java; Cela concerne la manière dont les flotteurs sont représentés en binaire, tels que définis par la norme IEEE 754.


4 Réponses :


29
votes

parce qu'un float ne peut contenir que 7 à 8 chiffres significatifs. C'est-à-dire qu'il n'a pas assez de bits pour représenter le nombre 2000000050 exactement, il est donc arrondi à 2000000000.

Spécifiquement parler, un float est composé de trois parties:

  • le bit de signalisation (1 bit)
  • l'exposant (8 bits)
  • Le signification (24 bits, mais seulement 23 bits sont stockés depuis le MSB du signaland, c'est toujours 1)

    Vous pouvez penser à un point flottant comme la voie de l'ordinateur faire la notation scientifique, mais en binaire.

    La la précision est égale à journal (2 ^ Nombre de bits significatifs) . Cela signifie qu'un float peut contenir journal (2 ^ 24) = 7.225 chiffres significatifs.

    Le nombre 2 000 000 050 a 9 chiffres significatifs. Le calcul ci-dessus nous dit qu'un signification 24 bits ne peut pas contenir de nombreux chiffres significatifs. La raison pour laquelle 2 000 000 000 œuvres car il n'y a que 1 chiffre significatif, il convient donc dans le signaland.

    Pour résoudre le problème, vous utiliseriez un double Comme il a un signaland 52 bits, qui est plus que suffisant pour représenter tous les numéros 32 bits possibles.


4 commentaires

Je ne comprends pas cette déclaration: la raison pour laquelle 2 000 000 000 œuvres car il n'y a qu'un chiffre important, il convient donc à ce que cela concerne le signaland.


@Fabriziom: Comprenez-vous pourquoi le nombre de 2 000 000 000 ne comporte que 1 chiffre significatif, mais le nombre de 2 000 000 050 comporte 9 chiffres significatifs?


ok donc est écarté en 2 ^ 9 (2 = signification 2 bits) (9 = Exponent 4 bits)


@Fabriziom: Les mathématiques sont en réalité un peu plus compliquées, mais c'est essentiellement le gist.



3
votes

dit clairement - 50 est une erreur d'arrondi lorsqu'un flotteur a une valeur de deux milliards.


3 commentaires

Clairement, mais inexactement :-)


@Stephen - Pouvez-vous élaborer pourquoi?


Parce que 50 simplement le nombre 50. Étant donné que les erreurs d'arrondi réelles sont les différences entre 200000000.0 et réel ((((float) 200000000) et entre 200000050.0 et < Code> réel ((flotteur) 200000050) .



2
votes

Cela pourrait vous aider à comprendre la situation si vous envisagez un programme (C ++) comme ci-dessous. Il affiche les groupes d'entiers successifs qui sont arrondies à la même valeur de flottaison: xxx

sortie: xxx

ceci indique que le point flottant est Assez précis que pour représenter tous les entiers de 1999999850 à 1999999935, enregistrant à tort leur valeur de 1999999872. Donc, pour d'autres valeurs. C'est la conséquence tangible de l'espace de stockage limité mentionné ci-dessus.


4 commentaires

La question n'est pas étiquetée c ++


@JeremyP: Je sais que, mais les formats de points flottants sont généralement normalisés sur une base matérielle et donc communs entre les langues, rendant les concepts applicables. J'arrive juste à aimer C ++ et je ne connais pas Java.


Oui, mais il n'est pas raisonnable de vous attendre à ce qu'un programmeur Java connaisse ce que les choses comme std :: Cout << Quelque chose réellement signifié.


@JeremyP: True, mais j'espère qu'ils pourraient transversir le programme avec la production et travailler suffisamment pour le réécrire en Java s'ils le souhaitent, ou du moins suivent le concept de base de la manière dont le double précision est utilisé pour passer à travers les valeurs que le flotteur ne peut pas représenter avec précision.



3
votes

Vous trouverez peut-être cette astuce pour trouver la prochaine valeur représentable intéressante. XXX PRE>

Imprime P>

The next float value after 2000000000 is 2000000128
The next double value after 2000000000.0000000 is 2000000000.0000002


1 commentaires

Soigné. Semble dépendre de la signification (voir dans la réponse de Silico) étant dans les bits les moins importants de l'INT. Je ne sais pas comment cela tient sur différentes architectures, mais peut-être que Java gère toujours de toute façon?