Convertire “1.79769313486232E + 308” a raddoppiare senza OverflowException?
Domanda
Ho questa stringa "1.79769313486232E + 308" e sto cercando di convertirlo in un valore numerico .NET (doppia?), Ma sono sempre l'eccezione di seguito. Sto usando Convert.ToDouble()
. Qual è il modo corretto di fare questa conversione?
OverflowException: valore era troppo grande o troppo piccola per una doppia
Soluzione
Il problema è probabilmente dovuto al fatto che Double.MaxValue
è stato convertito in una stringa, e quando la stringa è uscita, non tutte le cifre vengono emessi, invece è arrotondato. L'analisi di questo valore trabocca il doppio.
Utilizzando Double.TryParse
e successivamente controllando l'uguaglianza sulla stringa "1.79769313486232E + 308" in caso di fallimento e Double.MaxValue
sostituzione dovrebbe essere una rapida soluzione, se è necessario mantenere la stringa così com'è.
EDIT: Naturalmente, se non è necessario per mantenere la stringa così com'è, utilizzare il Andata identificatore di formato viaggio per produrre la stringa in primo luogo, come Jon descrive nella sua risposta .
Altri suggerimenti
Purtroppo questo valore è maggiore di double.MaxValue
, quindi l'eccezione.
Come codekaizen suggerisce, si potrebbe hard-code di un test per la stringa. Una migliore (IMO) alternativa se sei quello la produzione la stringa in primo luogo è quello di utilizzare la "r" di formato. Poi la stringa si produce sarà "1.7976931348623157E + 308", invece, che poi analizza correttamente:
string s = double.MaxValue.ToString("r");
double d = double.Parse(s); // No exception
Ovviamente questo è di nessun aiuto se non si ha il controllo dei dati -. Ma poi si dovrebbe capire è molto probabile che sia perdere i dati già in quel caso
Si può provare double.Parse()
o double.TryParse()
piuttosto che Convert.ToDouble()
, ma io non sono certo che si ottengono risultati migliori. Per inciso, la stringa che si fornisce è pari a double.MaxValue
, che è (ovviamente) il valore massimo che può essere contenuto in un doppio, così che è probabile in cui il vostro errore proviene. Virgola mobile tipi numerici sono meticolosi, quindi assumerebbero che una sorta di arrotondamento è in atto e spingendola fuori dei limiti del tipo.
Si potrebbe anche provare il tipo di dati decimal
. Si può avere più fortuna lì.
Ecco quello che mi è venuta. Grazie Jon Skeet e 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;
}
Dimostra il problema e una soluzione:
var s = double.MaxValue.ToString();
double d;
if (!double.TryParse(s, out d)) {
d = s.Equals(double.MaxValue) ? double.MaxValue : double.MinValue;
}
Qui un'implementazione più generico che rappresentava formattazione e culture diverso ed è più tollerante:
#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;
}
Questo numero è troppo grande per una doppia, come dice l'eccezione. Si sta andando a trovare un gran numero di libreria per gestire questo per voi, come non c'è nulla che io conosca nella biblioteca Net che gestisce numeri molto grandi.