Pergunta

Me deparei com este seguinte problema de aritmética.

Mas o resultado é diferente de operação matemática normal, Por que é assim?

double d1 = 1.000001;

double d2 = 0.000001;

Console.WriteLine((d1-d2)==1.0);
Foi útil?

Solução

Eu presumo que você achou a pergunta na página Brainteasers de Jon Skeet? As respostas são listadas e explicadas aqui , no mesmo site.

Por uma questão de referência, aqui está a resposta copiado a partir dessa página.


3) parva aritmética

Os computadores são feitos para ser bom em aritmética, não são? Por que esse print "False"?

double d1 = 1.000001; double d2 =
0.000001; Console.WriteLine((d1-d2)==1.0);

Resposta: Todos os valores aqui são armazenados como ponto flutuante binário. Enquanto 1.0 podem ser armazenados exatamente, 1,000001 é realmente armazenado como 1,0000009999999999177333620536956004798412322998046875 e 0,000001 é realmente armazenado como 0,000000999999999999999954748111825886258685613938723690807819366455078125. A diferença entre eles não é exatamente 1,0, e de fato a diferença não pode ser armazenado exatamente quer.


Outras dicas

A partir da entrada MSDN para Double.Equals :

Precision em comparações

O método Equals deve ser usado com cautela, porque dois aparentemente os valores equivalentes pode ser devido desigual à precisão diferentes dos dois valores. Os seguintes exemplos de relatórios que o valor Duplo 0,3333 eo Duplo voltou dividindo 1 por 3 são desigual.

...

Em vez de comparar a igualdade, uma técnica recomendada envolve definição de uma margem aceitável de diferença entre dois valores (tal como 0,01% de um dos valores). Se o valor absoluto da diferença entre os dois valores é inferior ou igual à margem, a diferença é provável que seja devido a diferenças na precisão e, portanto, os valores são susceptíveis de ser igual. Os seguintes exemplo usa essa técnica para comparar .33333 e 1/3, os dois valores Double que o exemplo de código anterior encontrada para ser desigual.

Se você precisa fazer um monte de comparações "igualdade" que poderia ser uma boa idéia para escrever uma função auxiliar ou método de extensão pouco em .NET 3.5 para comparar:

public static bool AlmostEquals(this double double1, double double2, double precision)
{
    return (Math.Abs(double1 - double2) <= precision);
}

Isto poderia ser usado da seguinte maneira:

double d1 = 1.000001;

double d2 = 0.000001;

bool equals = (d1 - d2).AlmostEquals(1.0, 0.0000001);

Veja esta questão muito semelhante: C # .NET: é seguro para verificar valores de ponto para a igualdade flutuante para 0

?

É porque os computadores fazer matemática na base 2, e, portanto, muitas decimais números de ponto flutuante não pode ser representado exatamente com um número limitado de dígitos.

Como você está usando números de ponto flutuante.

http://docs.sun.com/source/806-3568 /ncg_goldberg.html

Se você está fazendo tais aritmética em sua aplicação, a decimal tipo deve ser usado

decimal d1 = 1.000001M;

decimal d2 = 0.000001M;

Console.WriteLine((d1 - d2) == 1.0M); // evaluates as true

isto pode ser devido à flutuação problemas de precisão ponto como pode ser que o seu resultado não é exatamente 1.0, mas talvez algo como 1,000000000001

Isso acontece porque flutuante tipos de ponto de armazenar números usando uma base de dois e não uma representação de base dez. Isto tem como consequência que o dobro não é capaz de armazenar valores como 0,1 exatamente. Por exemplo 0.1 é representado pelo valor único 0,100000001490116119384765625.

Você tem que usar Decimal para se livrar do erro.

Isto é devido à maneira que números de ponto flutuante trabalhar na CPU, não é C # específico. Consulte este entrada da Wikipedia e do papel aqui para mais informações.

A resposta curta é que os números de ponto flutuante não são armazenadas como uma representação exata, de modo a fazer uma comparação usando "==" não funciona da maneira que você está tentando usá-lo.

Veja o que docs python tem que saym o problema é o mesmo para ambos:

http://docs.python.org/tutorial/floatingpoint.html

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