Преобразовать "1.79769313486232E + 308" в двойное число без исключения OverflowException? - PullRequest
10 голосов
/ 20 апреля 2009

У меня есть строка «1.79769313486232E + 308», и я пытаюсь преобразовать ее в числовое значение .NET (double?), Но получаю следующее исключение Я использую Convert.ToDouble(). Как правильно сделать это преобразование?

OverflowException: значение было либо слишком большим, либо слишком маленьким для Double

Ответы [ 7 ]

21 голосов
/ 20 апреля 2009

К сожалению, это значение больше double.MaxValue, следовательно, исключение.

Как предполагает codekaizen, вы можете жестко закодировать тест для строки. Лучшая альтернатива (IMO), если вы производите строку, в первую очередь, это использовать спецификатор формата "r". Тогда вместо строки, которую вы создадите, будет «1.7976931348623157E + 308», что затем будет правильно проанализировано:

string s = double.MaxValue.ToString("r");
double d = double.Parse(s); // No exception

Очевидно, что это не поможет, если у вас нет контроля над данными - но тогда вы должны понимать, что в этом случае вы, скорее всего, потеряете данные.

11 голосов
/ 20 апреля 2009

Проблема, вероятно, связана с тем, что Double.MaxValue был преобразован в строку, и когда строка выводится, выводятся не все цифры, вместо этого она округляется. Синтаксический анализ этого значения переполняет double.

Использование Double.TryParse и последующая проверка равенства в строке «1.79769313486232E + 308» в случае сбоя и замена Double.MaxValue должны быть быстрым обходным решением, если вам нужно сохранить строку такой, какая она есть.

РЕДАКТИРОВАТЬ: Конечно, если вам не нужно сохранять строку такой, какая она есть, используйте спецификатор формата Round Trip , чтобы сначала создать строку, как описывает Джон в своем ответе .

1 голос
/ 17 мая 2012

Демонстрирует проблему и решение:

var s = double.MaxValue.ToString();
double d;
if (!double.TryParse(s, out d)) {
    d = s.Equals(double.MaxValue) ? double.MaxValue : double.MinValue;
}
1 голос
/ 20 апреля 2009

Вот что я придумал. Спасибо Джону Скиту и кодекайзену.

private double convertToDouble(string str)
{
    double dbl;

    if (double.TryParse(str, out dbl))
        return dbl;

    if (str == "1.79769313486232E+308")
        return double.MaxValue;

    return double.MinValue;
}
1 голос
/ 20 апреля 2009

Вы можете попробовать double.Parse() или double.TryParse() вместо Convert.ToDouble(), но я не уверен, что вы получите лучшие результаты. Кстати, указанная вами строка равна double.MaxValue, что является (конечно) максимальным значением, которое может содержаться в двойном значении, так что, скорее всего, это ваша ошибка. Числовые типы с плавающей точкой являются привередливыми, поэтому я предположил бы, что происходит какое-то округление и выталкивает его за пределы типа.

Вы также можете попробовать тип данных decimal. Возможно, вам повезет больше.

0 голосов
/ 13 мая 2018

Вот более общая реализация, которая представляет различные форматирования и культуры и является более терпимой:

#region MatchDoubleMinMaxValuesRegex
/// <summary>
/// This regex matches strings which represents either a <see cref="double.MinValue"/> or a <see cref="double.MaxValue"/>.
/// If it is a <see cref="double.MinValue"/> then the group "isNegative" will be matched as <see cref="Group.Success"/>.
/// </summary>
private static readonly Regex MatchDoubleMinMaxValuesRegex = new Regex(
    @"
        ^
        (?>(?<isNegative>-)|\+?)
        1
        (?>[,.]?)
        79769313486232
        (?>
            [eE]\+308|
            0{294}(?>[,.]|$)
        )
    ",
    RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace
);
#endregion

/// <summary>
/// Converts the string representation of a number in a specified culture-specific format to its double-precision floating-point number equivalent.
/// <para>This implementation is more tolerant compared to the native double.Parse implementation:
/// strings representing <see cref="double.MinValue"/> and <see cref="double.MaxValue"/> can be parsed without <see cref="OverflowException"/>.</para>
/// </summary>
/// <param name="s">A string that contains a number to convert.</param>
/// <param name="cultureInfo">For some type conversions optional culture information that shall be used to parse the value.
/// If not specified, then the Current Culture will be used.</param>
/// <param name="numberStyles">For some type conversions optional number style configuration that shall be used to parse the value.
/// If not specified, then the default will be used.</param>
/// <returns>A double-precision floating-point number that is equivalent to the numeric value or symbol specified in <paramref name="s"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="s"/> is <c>null</c>.</exception>
/// <exception cref="FormatException"><paramref name="s"/> does not represent a number in a valid format.</exception>
/// <exception cref="OverflowException"><paramref name="s"/> represents a number that is less than <see cref="double.MinValue"/> or greater than <see cref="double.MaxValue"/>.</exception>
public static double ParseDoubleEx(string s, CultureInfo cultureInfo = null, NumberStyles? numberStyles = null)
{
    // Try parse
    double tempValue;
    bool parseSuccess = (numberStyles != null)
        ? double.TryParse(s, numberStyles.Value, cultureInfo, out tempValue)
        : double.TryParse(s, NumberStyles.Any, cultureInfo, out tempValue);

    // If parsing failed, check for Min or Max Value (by pattern)
    if (parseSuccess == false)
    {
        Match match = MatchDoubleMinMaxValuesRegex.Match(s);
        if (match.Success == true)
            tempValue = (match.Groups["isNegative"].Success == false)
                ? double.MaxValue
                : double.MinValue;
        else
            throw new OverflowException("A double-precision floating-point number that is equivalent to the numeric value or symbol specified in s.");
    }

    return tempValue;
}
0 голосов
/ 20 апреля 2009

Это число слишком велико для двойника, как говорит исключение. Вам придется найти библиотеку большого числа, чтобы справиться с этим, поскольку я ничего не знаю о библиотеке .Net, которая обрабатывает очень большие числа.

...