【问题标题】:Convert "1.79769313486232E+308" to double without OverflowException?在没有OverflowException的情况下将“1.79769313486232E+308”转换为double?
【发布时间】:2009-04-20 04:43:13
【问题描述】:

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

OverflowException: 值对于 Double 来说太大或太小

【问题讨论】:

    标签: c# .net double


    【解决方案1】:

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

    正如 codekaizen 建议的那样,您可以对字符串的测试进行硬编码。如果您首先生产字符串,则更好的(IMO)替代方案是使用“r”格式说明符。那么您生成的字符串将改为“1.7976931348623157E+308”,然后正确解析:

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

    如果您无法控制数据,显然这无济于事 - 但您应该明白,在这种情况下,您可能已经丢失了数据。

    【讨论】:

      【解决方案2】:

      这个问题很可能是因为Double.MaxValue被转换为字符串,而当字符串输出的时候,并不是所有的数字都输出,而是四舍五入。解析这个值会溢出双精度。

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

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 还是直接使用double.MaxValue?或者对该特定字符串进行字符串测试并替换 double.MaxValue,因为它显然是一种特殊情况。
        • 十进制根本不起作用。 Decimal.MaxValue
        【解决方案4】:

        这是我想出的。感谢 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;
        }
        

        【讨论】:

          【解决方案5】:

          展示问题和解决方案:

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

          【讨论】:

          • 这是错误的解决方案!如果 TryParse 返回 false,则 result 的值为 0。
          【解决方案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】:

            我有时会收到相同的号码。以下是我的解决方法。

            var str = "1.79769313486232E+308"; var dbl = double.Parse(str.Replace("E+", ""));

            【讨论】:

            • 哦,您的答案会默默地错误地解析字符串的预期值。只需删除 Exponentiation 符号将产生一个完全不同的数字而不会引发错误。 OP 得到的例外是有充分理由的 - 对于 .NET 双数据类型而言,这个数字太大了。
            【解决方案8】:

            正如例外所说,这个数字对于双倍来说太大了。您将不得不找到一个大数字库来为您处理这个问题,因为我所知道的 .Net 库中没有任何东西可以处理非常大的数字。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-11-22
              • 2017-05-27
              • 2018-08-15
              • 2021-10-24
              • 1970-01-01
              相关资源
              最近更新 更多