Recentemente, tive que serializar um duplo no texto e depois recuperá-lo. O valor parece não ser equivalente:
double d1 = 0.84551240822557006;
string s = d1.ToString("R");
double d2 = double.Parse(s);
bool s1 = d1 == d2;
// -> s1 is False
Mas, de acordo com o MSDN: Strings de formato numérico padrão , a opção "R" deve garantir segurança de ida e volta.
O especificador de formato de ida e volta ("R") é usado para garantir que um valor numérico convertido em uma seqüência de caracteres seja analisado novamente no mesmo valor numérico
Por quê isso aconteceu?
Respostas:
Eu encontrei o bug.
O .NET faz o seguinte em
clr\src\vm\comnumber.cpp
:DoubleToNumber
é bem simples - basta chamar_ecvt
, que está no tempo de execução C:Acontece que
_ecvt
retorna a string845512408225570
.Observe o zero à direita? Acontece que faz toda a diferença!
Quando o zero está presente, o resultado é analisado novamente
0.84551240822557006
, que é o seunúmero original - portanto, ele é igual e, portanto, somente 15 dígitos são retornados.No entanto, se eu truncar a string nesse zero para
84551240822557
, então eu volto0.84551240822556994
, que não é o seu número original e, portanto, retornaria 17 dígitos.Prova: execute o seguinte código de 64 bits (a maioria dos quais extraí do Microsoft Shared Source CLI 2.0) no seu depurador e examine
v
no final demain
:fonte
+1
. Este código é de shared-source-cli-2.0, certo? Este é o único pensamento que encontrei.Parece-me que isso é simplesmente um bug. Suas expectativas são inteiramente razoáveis. Eu o reproduzi usando o .NET 4.5.1 (x64), executando o seguinte aplicativo de console que usa minha
DoubleConverter
classe.DoubleConverter.ToExactString
mostra o valor exato representado por umdouble
:Resultados no .NET:
Resultados no Mono 3.3.0:
Se você especificar manualmente a seqüência de caracteres de Mono (que contém o "006" no final), o .NET analisará isso de volta ao valor original. Para isso, parece que o problema está no
ToString("R")
manuseio e não na análise.Conforme observado em outros comentários, parece que isso é específico para execução no CLR x64. Se você compilar e executar o código acima, segmentando x86, tudo bem:
... você obtém os mesmos resultados que com o Mono. Seria interessante saber se o bug aparece no RyuJIT - eu não o tenho instalado no momento. Em particular, eu posso imaginar isso possivelmente ser um bug JIT, ou é bem possível que existem inteiros implementações diferentes das partes internas do
double.ToString
baseados na arquitetura.Sugiro que você registre um bug em http://connect.microsoft.com
fonte
ToString()
? Como eu tentei substituir o valor codificado comrand.NextDouble()
e não houve problema.ToString("R")
conversão. ExperimenteToString("G32")
e observe que ele imprime o valor correto.Recentemente, estou tentando resolver esse problema . Conforme indicado no código , o double.ToString ("R") tem a seguinte lógica:
Nesse caso, double.ToString ("R") escolheu incorretamente o resultado na precisão de 15 para que o erro ocorra. Há uma solução oficial no documento do MSDN:
Portanto, a menos que esse problema seja resolvido, você deve usar double.ToString ("G17") para fazer a ronda.
Atualização : agora há um problema específico para rastrear esse bug.
fonte