Почему Double.TryParse() возвращает false для строки, содержащей double.MaxValue или double.MinValue?

У меня есть статический метод, который берет строку для ввода и возвращает исходную строку ввода, если строка представляет число. Если строка не представляет число, входная строка обрабатывается и возвращается преобразованная строка. Я пишу тестовые примеры. Я пытаюсь проверить, что строка ввода, содержащая либо ******.MinValue, либо ******.MaxValue, возвращается без изменений. Я прочитал несколько форумов, включая StackOverflow, и придумал следующую логику:

string ******Max = ******.MaxValue.ToString();
****** d;
CultureInfo cultureInfo = new CultureInfo("en-US", true);
if (******.TryParse(******Max, NumberStyles.Any, cultureInfo.NumberFormat, out d))
{
 Console.WriteLine("parsed");
}
else
{
 Console.WriteLine("couldn't parse");
}

Проблема: ******.TryParse() всегда возвращает false. Я вызвал TryParse() по-разному, но результат всегда один и тот же, false.

Эта логика работает, если я использую decimal.MinValue(), int.MinValue() или float.MinValue().

Может кто-нибудь сказать мне, почему моя логика не работает для ******.MinValue?

4 ответа

Это из-за того, как хранятся и отображаются номера с плавающей запятой. Значение округляется, когда оно превращается в читаемую пользователем строку, а для ******.MaxValue оно округляется, так что оно больше не подходит для ******.

Вы можете использовать формат "R" в обратном направлении, чтобы превратить значение в строку, которая всегда может быть проанализирована с тем же значением, поскольку она добавляет дополнительную точность до тех пор, пока не вернется правильное значение. Кроме того, используйте ту же культуру при форматировании числа в качестве синтаксического анализа, чтобы избежать различий в культуре:

CultureInfo cultureInfo = new CultureInfo("en-US", true);
string ******Max = ******.MaxValue.ToString("R", cultureInfo);
Console.WriteLine(******Max);
****** d;
if (******.TryParse(******Max, NumberStyles.Any, cultureInfo.NumberFormat, out d)) {
 if (d == ******.MaxValue) {
 Console.WriteLine("parsed");
 } else {
 Console.WriteLine("value changed");
 }
} else {
 Console.WriteLine("couldn't parse");
}

Вывод:

1.7976931348623157E+308
parsed

Edit:

Я добавил вывод строки и проверил, что анализируемое значение на самом деле все еще является MaxValue.


В вашей логике нет ничего плохого, это просто ограничение API ******.TryParse. Из документации

Обычно, если вы передаете метод ******.TryParse строку, созданную вызовом метода ******.ToString, возвращается исходное двойное значение. Однако из-за потери точности значения могут быть не равными. Кроме того, попытка проанализировать строковое представление MinValue или MaxValue вызывает исключение OverflowException, как показано в следующем примере.

Документация, по-видимому, взята из метода Parse и применяется к TryParse, поскольку TryParse не выбрасывает. Но пример кода, следующий за pargraph, использует TryParse и ожидает, что он потерпит неудачу для MaxValue и MinValue


Я заинтересовался этим вопросом и обнаружил, что если вы добавите E20 в ToString, тогда он будет работать.

******.MaxValue.ToString("E20")

Интересный вопрос.

UPDATE:

Я тестирую равенство между d (разобранным двойным) и ******.MaxValue, и они равны.

var abc = ******.Parse(******.MaxValue.ToString("E20"));
abc.Dump();
****** d;
CultureInfo cultureInfo = new CultureInfo("en-US", true);
if (******.TryParse(******.MaxValue.ToString("E20"), NumberStyles.Any, cultureInfo.NumberFormat, out d)) Console.WriteLine("parsed");
else Console.WriteLine("couldn't parse");
if(d == ******.MaxValue) Console.WriteLine("parsed value is equal to MaxValue");
else Console.WriteLine("parsed value is NOT equal to MaxValue");


Проблема заключается в округлении метода ToString(). Фактический MaxValue в соответствии с документацией составляет 1.7976931348623157E + 308, но ToString() этого дает вам 1,79769313486232E + 308, который округлен и, следовательно, слишком велик для синтаксического анализа.

licensed under cc by-sa 3.0 with attribution.