将“1.79769313486232E+308”转换为双精度而不发生 OverflowException?

StackOverflow https://stackoverflow.com/questions/766918

  •  12-09-2019
  •  | 
  •  

我有这个字符串“1.79769313486232E+308”,并尝试将其转换为 .NET 数值(双精度?),但出现以下异常。我在用 Convert.ToDouble(). 。进行此转换的正确方法是什么?

溢出异常:对于 Double 来说值太大或太小

有帮助吗?

解决方案

问题可能是由于以下事实造成的: Double.MaxValue 转换为字符串,输出字符串时,并不是输出所有的数字,而是四舍五入。解析该值会溢出双精度值。

使用 Double.TryParse 然后检查字符串“1.79769313486232E+308”的相等性,以防失败并替换 Double.MaxValue 如果您需要保持字符串原样,应该是一个快速的解决方法。

编辑:当然,如果您不需要保持字符串原样,请使用 往返格式说明符 首先生成字符串,如 乔恩在他的回答中描述了.

其他提示

不幸的是该值大于double.MaxValue更大,因此该异常。

作为codekaizen表明,您可以硬编码的字符串进行测试。如果你是一个更好的(IMO)替代的生产的摆在首位的字符串是使用“R”格式说明。然后,你产生字符串将是“1.7976931348623157E + 308”,而不是,然后解析正确:

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

显然,这没有帮助,如果你没有对数据的控制 - 但你应该明白你可能是在这种情况下,已经丢失数据

您可以尝试double.Parse()double.TryParse()而非Convert.ToDouble(),但我不能确定你会得到更好的结果。顺便说一句,您提供的字符串等double.MaxValue,这是(当然)可以包含在双最大值,所以这是有可能在您的错误的来源。浮点数字类型是挑剔,所以我假设某种舍入的正在发生,将其推类型的边界之外。

您也可以尝试decimal数据类型。您可能有更好的运气那里。

下面是我想出了。感谢乔恩斯基特和codekaizen。

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;
}

演示问题和解决方案:

var s = double.MaxValue.ToString();
double d;
if (!double.TryParse(s, out d)) {
    d = s.Equals(double.MaxValue) ? double.MaxValue : double.MinValue;
}

下面的更通用实现其代表不同的格式和文化和更耐受:

#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;
}

这个数字太大了一倍,作为例外说。你将不得不寻找大量的库来处理,对于你,因为没有什么东西是我所知道的在处理非常大的数字。净库。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top