Récemment, j'ai dû sérialiser un double en texte, puis le récupérer. La valeur ne semble pas être équivalente:
double d1 = 0.84551240822557006;
string s = d1.ToString("R");
double d2 = double.Parse(s);
bool s1 = d1 == d2;
// -> s1 is False
Mais selon MSDN: Standard Numeric Format Strings , l'option "R" est censée garantir la sécurité aller-retour.
Le spécificateur de format aller-retour ("R") est utilisé pour garantir qu'une valeur numérique convertie en chaîne sera analysée à nouveau dans la même valeur numérique.
Pourquoi est-ce arrivé?
Réponses:
J'ai trouvé le bogue.
.NET effectue les opérations suivantes dans
clr\src\vm\comnumber.cpp
:DoubleToNumber
est assez simple - il appelle simplement_ecvt
, qui est dans le runtime C:Il s'avère que
_ecvt
retourne la chaîne845512408225570
.Remarquez le zéro final?Cela fait toute la différence!
Lorsque le zéro est présent, le résultat est analysé en retour
0.84551240822557006
, qui est votre numéro d' origine - il se compare donc égal, et par conséquent, seuls 15 chiffres sont renvoyés.Cependant, si je tronque la chaîne à ce zéro à
84551240822557
, alors je reviens0.84551240822556994
, ce qui n'est pas votre numéro d'origine, et par conséquent, il renverrait 17 chiffres.Preuve: exécutez le code 64 bits suivant (dont la plupart j'ai extrait de Microsoft Shared Source CLI 2.0) dans votre débogueur et examinez
v
à la fin demain
:la source
+1
. Ce code provient de shared-source-cli-2.0, non? C'est le seul que j'ai trouvé.Il me semble que ce n'est qu'un bug. Vos attentes sont tout à fait raisonnables. Je l'ai reproduit en utilisant .NET 4.5.1 (x64), en exécutant l'application console suivante qui utilise ma
DoubleConverter
classe.DoubleConverter.ToExactString
montre la valeur exacte représentée par undouble
:Résultats dans .NET:
Résultats en Mono 3.3.0:
Si vous spécifiez manuellement la chaîne de Mono (qui contient le «006» à la fin), .NET analysera la valeur d'origine. Il semble que le problème réside dans le
ToString("R")
gestion plutôt que dans l'analyse.Comme indiqué dans d'autres commentaires, il semble que cela soit spécifique à l'exécution sous le CLR x64. Si vous compilez et exécutez le code ci-dessus ciblant x86, tout va bien:
... vous obtenez les mêmes résultats qu'avec Mono. Il serait intéressant de savoir si le bogue apparaît sous RyuJIT - je ne l'ai pas installé moi-même pour le moment. En particulier, je peux imaginer que cela pourrait être un bogue JIT, ou il est tout à fait possible qu'il existe des implémentations entièrement différentes des composants internes de
double.ToString
basés sur l'architecture.Je vous suggère de déposer un bug sur http://connect.microsoft.com
la source
ToString()
? Comme j'ai essayé de remplacer la valeur codée en dur parrand.NextDouble()
et il n'y avait aucun problème.ToString("R")
conversion. Essayez deToString("G32")
remarquer qu'il imprime la valeur correcte.Récemment, j'essaye de résoudre ce problème . Comme indiqué dans le code , le double.ToString ("R") a la logique suivante:
Dans ce cas, double.ToString ("R") a mal choisi le résultat avec une précision de 15 donc le bogue se produit. Il existe une solution de contournement officielle dans le document MSDN:
Donc, à moins que ce problème ne soit résolu, vous devez utiliser double.ToString ("G17") pour aller-retour.
Mise à jour : il y a maintenant un problème spécifique pour suivre ce bogue.
la source