تحويل "1.79769313486232E + 308" للمضاعف دون overflowException؟

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

  •  12-09-2019
  •  | 
  •  

سؤال

لدي هذه السلسلة "1.79769313486232E + 308" وأنا أحاول تحويلها إلى قيمة رقمية .NET (مزدوجة؟) لكنني أحصل على الاستثناء أدناه. انا استخدم Convert.ToDouble(). وبعد ما هي الطريقة الصحيحة للقيام بذلك التحويل؟

OverflowException: كانت القيمة إما كبيرة جدا أو صغيرة جدا لفترة مزدوجة

هل كانت مفيدة؟

المحلول

من المرجح أن تكون المشكلة بسبب حقيقة ذلك 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 نوع البيانات. قد يكون لديك حظ أفضل هناك.

هنا هو ما توصلت إليه. شكرا جون 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;
}

هنا تنفيذ أكثر عمومية تمثل التنسيق والثقافات المختلفة وهو أكثر تسامحا:

#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