2015-11-23 17 views
32

Proszę zobaczyć mój przykład poniżej.Dlaczego konwersja między ciągiem a zmiennoprzecinkowym jest nieprawidłowa?

float maxFloat = float.MaxValue; 
string s = maxFloat.ToString(); 
float result = float.Parse(s); // same with Convert.ToSingle(s); 

bool mustEqual = (maxFloat == result); 
// It returns FALSE, why? 
+17

Dmitry ma odpowiedź, ale zauważ, że porównywanie elementów pływających dla dokładnej równości jest prawie zawsze błędem - powinieneś wybrać rodzaj precyzji, jaki chcesz, upewnij się, że jest w zakresie możliwości danego typu danych, i wykonaj porównanie tylko z podana dokładność. – Luaan

+16

@Luaan Nie jest błędem, jeśli upewnisz się, że podróże w obie strony nie zmieniają wartości, co jest ważną rzeczą, której należy chcieć od serializacji i deserializacji. Nawet jeśli późniejsze obliczenia nie są dokładnie przewidywalne z powodu zaokrągleń, nie ma powodu, aby akceptować błąd zaokrąglania w krokach, które mogą być dokładne (takie jak float -> string -> float roundtrip). – delnan

+2

Porównywanie wartości zmiennoprzecinkowych dla równości jest prawie * zawsze * a *** bug ***. – RBarryYoung

Odpowiedz

47

Należy użyć "R" ciąg formatu:

https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx.

https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx#RFormatString

"R" lub "R" Round-trip Wynik: ciąg znaków, który może w obie strony do identycznym numerem. Obsługiwane przez: Single, Double i BigInteger. Precyzyjny specyfikator: Ignorowany.

float maxFloat = float.MaxValue; 
    string s = maxFloat.ToString("R"); // <- "R" 
    float result = float.Parse(s); 

    bool mustEqual = (maxFloat == result); 
+0

Trzymaj się, czy to nie znaczy, że * nie jest * oficjalnie wspierany przez float? – deworde

+9

@deworde: 'float' i' Single' są synonimami: https://msdn.microsoft.com/en-US/library/b1e65aza.aspx (jak również 'double' i' Double'). "Typ float ... .NET Framework type System.Single" –

29

// It returns FALSE, why?

Ponieważ float.ToString() wyprowadza 7-cyfrowy numer precyzję domyślnie, więc float.MaxValue który ma wartość 3.40282347E+38 (9-cyfrową precyzją) zostanie zaokrąglona do 3.402823E+38 a twój czek nie powiedzie się, ponieważ oczywiście 3.402823E+38 != 3.40282347E+38.

Jeśli wyraźnie określono specyfikator formatu, aby wyprowadzić float.MaxValue z dokładnością 9-cyfrową, np. float.MaxValue.ToString("G9"), twoje sprawdzenie się powiedzie.

Powiązane problemy