我有这个字符串“1.79769313486232E+308”并试图将其转换为 .NET 数值(双精度值?),但出现以下异常。我正在使用Convert.ToDouble()
. 进行这种转换的正确方法是什么?
溢出异常:对于 Double 而言,值太大或太小
不幸的是,这个值大于double.MaxValue
,因此例外。
正如 codekaizen 建议的那样,您可以对字符串的测试进行硬编码。如果您是首先生成字符串的人,那么更好的(IMO)替代方法是使用“r”格式说明符。然后您生成的字符串将改为“1.7976931348623157E+308”,然后正确解析:
string s = double.MaxValue.ToString("r");
double d = double.Parse(s); // No exception
显然,如果您无法控制数据,那将无济于事——但您应该明白,在这种情况下,您可能已经丢失了数据。
问题可能是由于Double.MaxValue
转换为字符串,输出字符串时,并不是所有的数字都输出,而是四舍五入。解析这个值会溢出双精度值。
在失败的情况下使用Double.TryParse
并随后检查字符串“1.79769313486232E+308”的相等性Double.MaxValue
,如果您需要保持字符串原样,则替换应该是一种快速的解决方法。
编辑:当然,如果您不需要将字符串保持原样,请使用Round Trip 格式说明符首先生成字符串,正如Jon 在他的回答中所描述的那样。
您可以尝试double.Parse()
ordouble.TryParse()
而不是Convert.ToDouble()
,但我不确定您会得到更好的结果。顺便说一句,您提供的字符串等于double.MaxValue
,这(当然)是双精度中可以包含的最大值,因此这很可能是您的错误来自哪里。浮点数字类型很挑剔,所以我假设正在发生某种舍入并将其推到类型的范围之外。
您也可以尝试decimal
数据类型。在那里你可能会有更好的运气。
这是我想出的。感谢 Jon Skeet 和 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;
}
Here a more generic implementation which representing different formatting and cultures and is more tolerant:
#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;
}
我有时会收到相同的号码。这是我如何解决它的。
var str = "1.79769313486232E+308"; var dbl = double.Parse(str.Replace("E+", ""));
正如例外所说,这个数字对于双倍来说太大了。您将不得不找到一个大数字库来为您处理这个问题,因为我所知道的 .Net 库中没有任何东西可以处理非常大的数字。