Voici le code simplifié: est-il garanti que a == b code> est vrai fort>? p> < / p>
4 Réponses :
Oui. Les entiers 32 bits peuvent être représentés exactement sous forme de chiffres de points flottants de 64 bits. P>
Des références à la spécification, s'il vous plaît?
Je doute qu'il y ait quelque chose dans la spécification C # à propos de ce cas particulier, mais si vous regardez la spécification du format Binary64 IEEE 754, vous verrez qu'il utilise 52 bits pour encoder le signaland, ce qui signifie qu'il peut représenter des nombres entiers jusqu'à 2 ^ 52 - 1 code> exactement ... ou probablement plus que cela. Je ne suis pas tout à fait sûr.
Table de conversion numérique implicite (référence C #) ~ msdn.microsoft.com/en-us /Library/y5b434w4.aspx
En tout état de cause, même s'il y avait une erreur dans le calcul et i code> était une valeur "OFF", vous avez défini
A code> et
b code> à eux, ils ont donc la même valeur (potentiellement incorrecte). C'est comme demander si
double A = 1; double b = a; code>, alors fait
a == b code>? Les erreurs de double précision peuvent être méchantes, mais pas comme ça. Même si vous convertissiez de
long code> à
double code>, et que vous avez perdu la précision,
a code> et
b code> aurait la fois le Même valeur "incorrecte" - trouver cela dans la spécification est peut-être une question plus intéressante.
@Nigel: Les conversions numériques implicites sont la chose qui nous permet d'écrire "Double A = 1" mais ne dit rien de précision.
@Levanovd: "Les conversions de l'INT, de l'UTINT ou de flotter et de long à doubler peuvent causer une perte de précision, mais pas une perte de grandeur." (du lien)
@Nigel Whatling de sorte que cela signifie qu'ils tournent vers + ou - infini plutôt que de tronquer des autres langues? En C ++ INT64_T (double (valeur))
valeur code> a plus de 52 bits en utilisation et le jeu de bits le plus bas, la perte de précision provoque une perte de grandeur .
Wow, cela a été compliqué. Je ne pense pas que la citation de mon lien d'origine ait vraiment aidé (désolé @levanovd). Dans la langue C # Spec, cela va une autre: "Les autres conversions numériques implicites ne perdent jamais d'informations". Donc int to doubler ne perd rien. @Pete, je ne sais pas comment il se compare à C ++. Mais à la suite de l'exemple original, la valeur est une 32 bits int afin qu'elle n'aura jamais plus de 52 bits d'utilisation.
J'ai eu un badge à ce sujet qui me rappelait cette réponse de plus de cinq ans, et je voulais répondre à mon commentaire sur "Les erreurs de précision peuvent être méchantes, mais pas comme ça." Cela ne s'applique pas à C #, mais c'est une excellente lecture: GCC. gnu.org/bugzilla/show_bug.cgi?id=323#c109
J'ai ouvert Visual Studio, et je l'ai testé.
Voici mon code: P>
int i = 5; double t = i; double k = i; MessageBox.Show((i == t).ToString()); //true MessageBox.Show((k == t).ToString()); //true i += 5; t += 5; k = i; MessageBox.Show((i == t).ToString()); //true MessageBox.Show((k == t).ToString()); //true i += (int)Math.Round(5.6); t += 5.6; t = (int)Math.Round(t); k = i; MessageBox.Show((i == t).ToString()); //true MessageBox.Show((k == t).ToString()); //true i = int.MaxValue - 5438; t = int.MaxValue - 5438; k = i; MessageBox.Show((i == t).ToString()); //true MessageBox.Show((k == t).ToString()); //true i = (int)Math.Round(double.MaxValue); t = Math.Round(double.MaxValue); k = i; MessageBox.Show((i == t).ToString()); //false MessageBox.Show((k == t).ToString()); //false i = (int)Math.Round(double.MaxValue); t = i; k = i; MessageBox.Show((i == t).ToString()); //true MessageBox.Show((k == t).ToString()); //true
J'ai bownvoché parce que votre conclusion me semble assez dangereuse (même si vous avez probablement raison): Juste parce que vous avez testé Un scénario simple i> Un scénario simple ne signifie pas que ce sera toujours i > travail. (Vous avez testé 1 cas sur 2 ^ 32. Vous manquez d'une preuve inductive pour montrer que votre conclusion est également valable pour tous les autres entiers.) - Dès que vous commencez à faire des calculs de point flottant, vous êtes probablement aller introduire des erreurs d'arrondi. Heureusement, pour les entiers, ceux-ci sont si petits qu'ils sont probablement insignifiants dans la plupart des cas.
Contre-exemple: B> Tout d'abord, remplacez les ajouts avec i / = 2; t / = 2; code>. Deuxièmement, rendez les distributeurs dans votre test d'égalité explicite:
i == (int) t code> entraînera probablement toujours
vrai code>, car les mauvaises erreurs d'arrondi à virgule flottante sont arrondies . Otoh,
(double) i == t code> entraînera
faux code> avec les divisions ci-dessus par 2. - Conclusion: B> pendant que vous pouvez probablement < I> Store i> Un entier dans un
double code> sans perte de précision, ce n'est pas vrai dès que vous commencez à faire Computions i> Parce que vous introduisez des erreurs d'arrondi!
Avez-vous lu mon contre-exemple? Cela vous donne un cas où votre test ne fonctionnerait pas. Vos tests ne semblent fonctionner que parce que vous comptez sur la couche implicite de double code> à
int code> pour variable
t code> (et
k < / code>). Mais:
i code> et
t code> sera souvent pas i> égal! Vous ne faites que "voir" l'égalité parce que vous arrondissez les petites différences! Essayez de comparer ces valeurs comme
double code> s et voir ce qui se passe.
Désolé, je n'ai pas vu celui-là avant de poster mon édition. Vous avez raison. Mais la question des demandeurs était si les doubles seront égaux si elles obtiennent leurs valeurs du même Int, et elles le feront. Si vous effectuez des opérations sur l'int et sur le double après avoir défini leurs valeurs, elles ne seront plus égales, car le double peut stocker des nombres plus complexes.
Oui, vous pouvez stocker un numéro d'entiers (32 bits) dans un Cependant, dès que vous effectuez des calculs avec votre Résumer (quelque peu inexactement), une valeur à virgule flottante se compose de trois parties: un bit de signalisation, une partie de "fraction" (appelée la mantissa) et une partie "exposant". Ils sont mis ensemble à peu près comme suit: p>
valeur em> = -1 bit de signe em> sup> × fraction em> × 2 exponeent em> sup> p>
Vous pouvez stocker la valeur entière dans la partie "fraction" du double code> (qui correspond à 52 bits larges, ce qui est plus large pour un entier 32 bits. La partie "Exponent" peut simplement être réglé sur 0, car ce n'est pas nécessaire. P> double code> (numéro de point flottant 64 bits) sans perte de précision. P>
double code>, vous introduisez probablement des erreurs d'arrondi, c'est-à-dire une perte de précision. Ces erreurs seront probablement suffisamment petites afin qu'elles soient arrondies lorsque vous lancez votre
Double code> retour sur
int code> - mais l'erreur est là, alors en soyez conscient. < / p>
est-il garanti qu'un == B est vrai? p>
Oui. En effet, vous effectuez la même conversion deux fois et que vous avez donné son comportement déterministe, vous vous retrouverez avec les mêmes valeurs, quels que soient les mêmes valeurs, quels que soient les problèmes d'arrondi. P>
Nous pouvons généraliser votre question cependant, pour: P>
Pouvons-nous effectuer des opérations arithmétiques sur des valeurs entières 32 bits codées dans
double code> sans précision en vrac? p> blockQuote>
La réponse pour une telle question est également oui. P>
Une courte justification est que les opérations sur les bits de Mantissa (voir
http://fr.wikipedia.org/wiki/significand ) sont précis si cela n'est possible que si cela est possible et en cas de valeurs entières 32 bits, il est possible. P> L'histoire plus longue vient ici. Tant que votre valeur entière convient à 52 bits d'une partie de fraction appelée Mantissa (voir http: //fr.wikipedia .org / wiki / double_precision ) Tous les calculs sur les valeurs entière utilisant Double vont se comporter complètement OK. P>
Ceci est parce que votre numéro (disons 173 qui est
0000010101101b code> binaire) sera représenté comme
1.010110100000b * 2 ^ 7 code>, ce qui est précis. P>
Toutes les opérations sur MANTISSA sont directement en avant à mesure qu'elles correspondent à MANTUSSA. L'arrondi sur des entiers se produit lorsque le résultat d'une opération particulière ne correspond pas à la mantissa - par exemple. Vous multipliez 40 morceaux de MANTISSA par 40 bits de MANTISSA. L'arrondi sur les opérations de point flottant se produisent en outre lorsque des exposants sont bien différents. Dans ce cas, même une opération d'addition simple peut perdre de la précision, car les matissas sont décalés. P>
Retour aux entiers codés dans une double opération de division est précis, tant que le résultat est une valeur entière. Donc,
4.0 / 2.0 == 8.0 / 4.0 code> est également garanti d'être vrai. P>
Le problème commence lorsque votre numéro n'est pas entier. Mais même dans ce cas, les numéros sont garantis pour être représenté avec précision si elles sont une forme de
x / 2 ^ y code> et
x code> s'adapte dans 52 bits (par exemple,
3 / 4 code>
5/8 code>
345/1024 code>). Les opérations de ces numéros sont également précises données
y code> peuvent être égales pour les deux opérandes, de sorte que même: p>
xxx pré> est garanti pour être vrai. P >
Fait intéressant est que vous pouvez effectuer une opération sur des entiers signés de 54 bits en toute sécurité. En effet, vous avez un bit supplémentaire au début dont la signification est codée par l'exposant et un bit supplémentaire pour un signe. Maintenant -2 ^ 53 Qui serait Min_int en cas d'entier signé de 54 bits ne correspond pas à la mantissa, mais l'exposant fera le travail ici avec Mantissa pleine de zéros. P> blockQquote>
Pourquoi pas? Je voudrais sûrement savoir pourquoi si quelqu'un dit non!
Parce que par exemple 4.0 / 2.0! = 8,0 / 4.0 Dans un cas général en raison de problèmes de précision. Il n'y a pas de calcul dans mon problème pour que la question soit si elle aide à éviter ce problème.
Bien que techniquement correct, il s'agit d'un mauvais choix, car ces deux valeurs peuvent être représentées exactement par un type de point de double flottant IEEE 754.
@codaizen, oui, tu as raison, je sais ça. C'est un exemple extrêmement simplifié.
(1.0 / 3.0) * 5.0! = 5.0 / 3.0 serait probablement un meilleur choix.