Desculpe, essa pode ser uma pergunta fácil e estúpida, mas preciso saber para ter certeza.
Eu tenho essa if
expressão,
void Foo()
{
System.Double something = GetSomething();
if (something == 0) //Comparison of floating point numbers with equality
// operator. Possible loss of precision while rounding value
{}
}
Essa expressão é igual a
void Foo()
{
System.Double something = GetSomething();
if (something < 1)
{}
}
? Porque então eu posso ter um problema, inserindo o if
com, por exemplo, um valor de 0,9.
// Comparison of floating point numbers with equality // operator.
Você realmente precisava especificar isso? :)Respostas:
Bem, quão próximo você precisa que o valor esteja de 0? Se você passar por muitas operações de ponto flutuante que em "precisão infinita" podem resultar em 0, você pode acabar com um resultado "muito próximo" de 0.
Normalmente, nesta situação, você deseja fornecer algum tipo de épsilon e verificar se o resultado está exatamente dentro desse épsilon:
if (Math.Abs(something) < 0.001)
O epsilon que você deve usar é específico do aplicativo - depende do que você está fazendo.
Obviamente, se o resultado for exatamente zero, uma simples verificação de igualdade é adequada.
fonte
== 0
. Você tem um literal aí - que é bastante constante :)Se
something
foi atribuído a partir do resultado de uma operação diferente desomething = 0
então, é melhor usar:if(Math.Abs(something) < Double.Epsilon) { //do something }
Edit : Este código está errado. Epsilon é o menor número, mas não exatamente zero. Quando você deseja comparar um número a outro, precisa pensar em qual é a tolerância aceitável. Digamos que qualquer coisa além de 0,00001 você não se importe. Esse é o número que você usaria. O valor depende do domínio. No entanto, certamente nunca é Double.Epsilon.
fonte
Math.Abs(0.1f - 0.1d) < double.Epsilon
éfalse
double d = Math.Sqrt(10100)*2; double a = Math.Sqrt(40400); if(Math.Abs(a - d) < double.Epsilon) { Console.WriteLine("true"); }
Seu
something
é umdouble
, e você o identificou corretamente na linhaif (something == 0)
temos um
double
no lado esquerdo (lhs) e umint
no lado direito (rhs).Mas agora parece que você acha que lhs será convertido em um
int
, e então o==
sinal irá comparar dois inteiros. Não é isso que acontece. A conversão dedouble
paraint
é explícita e não pode acontecer "automaticamente".Em vez disso, acontece o oposto. O rhs é convertido em
double
, e então o==
sinal se torna um teste de igualdade entre duas duplas. Essa conversão é implícita (automática).É considerado melhor (por alguns) escrever
if (something == 0.0)
ou
if (something == 0d)
porque então é imediato que você está comparando duas duplas. No entanto, é apenas uma questão de estilo e legibilidade, porque o compilador fará a mesma coisa em qualquer caso.
Também é relevante, em alguns casos, introduzir uma "tolerância" como na resposta de Jon Skeet, mas essa tolerância também seria
double
. Ele poderia ser, obviamente,1.0
se você queria, mas ele não tem que ser [o mínimo estritamente positivo] inteiro.fonte
Se você simplesmente deseja suprimir o aviso, faça o seguinte:
if (something.Equals(0.0))
Claro, esta é uma solução válida apenas se você souber que a deriva não é uma preocupação. Costumo fazer isso para verificar se estou prestes a dividir por zero.
fonte
Eu não acho que seja igual, honestamente. Considere seu próprio exemplo: algo = 0,9 ou 0,0004. No primeiro caso será FALSE, no segundo caso será TRUE. Ao lidar com esses tipos, normalmente defino para mim a porcentagem de precisão e comparo dentro dessa precisão. Depende de suas necessidades. algo como...
if(((int)(something*100)) == 0) { //do something }
Espero que isto ajude.
fonte
Aqui está o exemplo que apresenta o problema (preparado no LinQPad - se você não tiver, use em
Console.Writeline
vez doDump
método):void Main() { double x = 0.000001 / 0.1; double y = 0.001 * 0.01; double res = (x-y); res.Dump(); (res == 0).Dump(); }
Tanto x como y são teoricamente iguais e iguais a: 0,00001, mas devido à falta de "precisão infinita", esses valores são ligeiramente diferentes. Infelizmente, um pouco o suficiente para retornar
false
ao comparar com 0 da maneira usual.fonte