代码之家  ›  专栏  ›  技术社区  ›  Eric Schoonover thSoft

将“1.79769313486232E+308”转换为双精度,无溢出异常?

  •  10
  • Eric Schoonover thSoft  · 技术社区  · 15 年前

    我有一个字符串“1.79769313486232E+308”,正试图将其转换为.NET数值(double?)但是我得到了下面的例外。我正在使用 Convert.ToDouble() . 进行这种转换的正确方法是什么?

    OverflowException:值对于Double太大或太小

    7 回复  |  直到 6 年前
        1
  •  11
  •   codekaizen    6 年前

    问题可能是由于 Double.MaxValue 已转换为字符串,当输出字符串时,并不是所有数字都输出,而是四舍五入。分析该值会溢出double。

    使用 Double.TryParse 随后检查“1.79769313486232E+308”字符串是否相等,以防出现故障并进行替换。 最大值 如果您需要保持字符串的原样,应该是一个快速的解决方法。

    编辑:当然,如果不需要保持字符串的原样,请使用 Round Trip format specifier 首先生成字符串,如 Jon describes in his answer .

        2
  •  21
  •   Jon Skeet    15 年前

    不幸的是,这个值大于 double.MaxValue 因此出现了例外。

    正如codekaizen所建议的,您可以对字符串的测试进行硬编码。如果你是更好的选择 生产 首先,字符串使用“r”格式说明符。然后,您生成的字符串将改为“1.7976931348623157E+308”,然后正确解析:

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

    显然,如果你没有控制数据的能力,那是没有帮助的——但是你应该明白,在这种情况下,你可能已经失去了数据。

        3
  •  1
  •   Adam Robinson    15 年前

    你可以试试 double.Parse() double.TryParse() 而不是 Convert.ToDouble() 但是我不确定你会得到更好的结果。顺便说一下,您提供的字符串等于 double.MaxValue ,这是(当然)可以包含在double中的最大值,所以这很可能是您的错误的来源。浮点数字类型是有限的,所以我假设正在进行某种取整,并将其推到类型边界之外。

    你也可以试试 decimal 数据类型。你在那里可能会有更好的运气。

        4
  •  1
  •   Eric Schoonover thSoft    15 年前

    这就是我想到的。感谢乔恩·斯基特和代码改善。

    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;
    }
    
        5
  •  1
  •   Corey Alix    12 年前

    演示问题和解决方案:

    var s = double.MaxValue.ToString();
    double d;
    if (!double.TryParse(s, out d)) {
        d = s.Equals(double.MaxValue) ? double.MaxValue : double.MinValue;
    }
    
        6
  •  0
  •   rittergig    6 年前

    这里有一个更通用的实现,它代表不同的格式和文化,并且更具宽容性:

    #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;
    }
    
        7
  •  -2
  •   Jamie Penney    15 年前

    这个数字太大了,不能翻倍,例外情况是这样说的。你必须找到一个大数字库来处理这个问题,因为在.NET库中,我对处理非常大的数字一无所知。