OverflowException を発生させずに「1.79769313486232E+308」を double に変換しますか?

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

  •  12-09-2019
  •  | 
  •  

質問

この文字列「1.79769313486232E+308」があり、それを .NET 数値 (double?) に変換しようとしていますが、以下の例外が発生します。使っています Convert.ToDouble(). 。この変換を行う適切な方法は何ですか?

オーバーフロー例外:値が Double に対して大きすぎるか小さすぎます

役に立ちましたか?

解決

この問題はおそらく次のような事実によるものです。 Double.MaxValue が文字列に変換されましたが、文字列が出力されるときに、すべての桁が出力されるわけではなく、丸められます。この値を解析すると double がオーバーフローします。

使用する Double.TryParse その後、文字列「1.79769313486232E+308」の等価性をチェックし、失敗した場合は置き換えます。 Double.MaxValue 文字列をそのままにしておく必要がある場合は、これが簡単な回避策になります。

編集:もちろん、文字列をそのままにしておく必要がない場合は、 ラウンドトリップ形式指定子 最初に文字列を生成します。 ジョンは答えの中で次のように説明しています.

他のヒント

残念ながら、この値は、したがって、例外double.MaxValueより大きい。

codekaizenあなたはハードコード文字列をテストすることができ、示唆しています。あなたがを生成する1なら(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;
}

その数は例外が言うように、二重のために大きすぎます。あなたは、私は非常に大きな数を扱うの.NETライブラリでの知っているものはないとして、あなたのためにそれを処理するために、多数のライブラリーを見つけるために持ってしようとしている。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top