Pergunta

Eu tenho essa string "1.79769313486232E + 308" e estou tentando convertê-lo para um valor numérico .NET (double?), Mas estou recebendo o abaixo exceção. Eu estou usando Convert.ToDouble(). O que é a maneira correta de fazer esta conversão?

OverflowException: Valor era muito grande ou muito pequeno para um casal

Foi útil?

Solução

O problema é provavelmente devido ao fato de que Double.MaxValue foi convertido para uma cadeia, e quando a corda está de saída, nem todos os dígitos são emitidos, em vez disso, é arredondado. Analisando este valor excede o dobro.

Usando Double.TryParse e, posteriormente, verificar a igualdade na cadeia "1.79769313486232E + 308" em caso de falha e substituindo Double.MaxValue deve ser uma solução rápida, se você precisa para manter a corda do jeito que está.

EDIT: Claro, se você não precisa manter a corda do jeito que está, use o Round Trip especificador de formato para produzir a cadeia no primeiro lugar, como Jon descreve em sua resposta .

Outras dicas

Infelizmente, este valor é maior do que double.MaxValue, daí a exceção.

Como codekaizen sugere, você poderia codificar um teste para a cadeia. A melhor (IMO) alternativa se você é o único produzindo a corda em primeiro lugar é usar o "r" especificador de formato. Em seguida, a cadeia que produzir será "1.7976931348623157E + 308" em vez disso, que, em seguida, analisa corretamente:

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

Obviamente isso não ajuda se você não tem controle sobre os dados -. Mas então você deve entender é provável que você estar perdendo dados já nesse caso

Você pode tentar double.Parse() ou double.TryParse() em vez de Convert.ToDouble(), mas eu não estou certo que você obterá melhores resultados. Aliás, a string que você fornecer é igual a double.MaxValue, que é (é claro) o valor máximo que pode ser contido em um duplo, de modo que é provável que o erro está vindo. De ponto flutuante tipos numéricos são mimados, então eu diria que algum tipo de arredondamento está ocorrendo e empurrando-o para fora dos limites do tipo.

Você também pode tentar o tipo de dados decimal. Você pode ter melhor sorte lá.

Aqui está o que eu vim acima com. Graças 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;
}

Demonstra o problema e uma solução:

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

Aqui uma implementação mais genérico que representa formatação e culturas diferentes e é mais tolerante:

#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;
}

Esse número é muito grande para um casal, como a exceção diz. Você vai ter que encontrar uma grande biblioteca número de lidar com isso para você, como não há nada que eu saiba na biblioteca .Net que lida com números muito grandes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top