Teste se um número de ponto flutuante é um número inteiro
-
02-07-2019 - |
Pergunta
Este código funciona (C # 3)
double d;
if(d == (double)(int)d) ...;
- Existe uma maneira melhor de fazer isso?
- Por razões estranhas que eu quero evitar a dupla elenco tão; o que maneiras agradáveis ??existe outros do que isso? (Mesmo que eles não são tão bons)
Nota: Várias pessoas apontaram o ponto (importante) que == é muitas vezes reclassificação problemática ponto flutuante. Nestes casos espero valores no intervalo de 0 a algumas centenas e eles deveriam ser inteiros (não ints são erros) por isso, se esses pontos "não deve" ser um problema para mim.
Solução
d == Math.Floor(d)
faz a mesma coisa em outras palavras.
Nota: Esperamos que você está ciente de que você tem que ter muito cuidado ao fazer esse tipo de coisa; flutuadores / duplos será muito fácil acumular erros minúsculos que fazem comparações exatas (como este) falhar por nenhuma razão óbvia.
Outras dicas
Se o seu duplo é o resultado de um outro cálculo, você provavelmente vai querer algo como:
d == Math.Floor(d + 0.00001);
Assim, se houve um ligeiro erro de arredondamento, ele ainda vai corresponder.
Isso funcionaria eu penso:
if (d % 1 == 0) {
//...
}
Eu não posso responder a parte espec�ico C # da questão, mas devo salientar que você provavelmente está faltando um problema genérico com números de ponto flutuante.
Geralmente, integerness não é bem definida em carros alegóricos. Pela mesma razão que a igualdade não é bem definida em carros alegóricos. Cálculos de ponto flutuante normalmente incluem tanto erros de arredondamento e de representação.
Por exemplo, 1.1 + 0.6 != 1.7
.
Sim, isso é apenas a maneira como números de ponto flutuante de trabalho.
Aqui, 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16
.
A rigor, a coisa mais próxima para comparação de igualdade que você pode fazer com flutuadores está comparando-os até uma precisão escolhido .
Se isto não é suficiente, você deve trabalhar com uma representação número decimal, com uma representação número de ponto flutuante com built-in margem de erro, ou com os cálculos simbólicos.
Se você está indo só para convertê-lo, a resposta de Mike F / Khoth é bom, mas não chega a responder à sua pergunta. Se você estiver indo para realmente teste, e é realmente importante, eu recomendo que você implementar algo que inclui uma margem de erro.
Por exemplo, se você está pensando em dinheiro e você quer teste para valores até mesmo dólar, você pode dizer (seguindo o padrão de Khoth):
if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)
Em outras palavras, tomar o valor absoluto da diferença do valor e da representação inteira e garantir que ele é pequeno.
Você não precisa extra (duplo) lá dentro. Isso funciona:
if (d == (int)d) {
//...
}
Use Math.Truncate ()
Um teste simples, como 'x == floor (x)' é matematicamente assegurado ao trabalho corretamente, para qualquer número de precisão fixo FP.
Todas as codificações FP de precisão fixa legais representam números reais distintos, e assim, para cada inteiro x, há no máximo FP codificação de uma precisão fixa que partidas exatamente.
Portanto, para cada inteiro x que pode ser representada de tal maneira, temos x == floor (x), necessariamente, uma vez que floor (x) por volta definição o maior número FP y tal que y <= x e y representa um número inteiro; assim floor (x) deve retornar x.
Isso permitirá que você escolha o que precisão você está procurando, mais ou menos metade de um carrapato, a conta para flutuante deriva ponto. A comparação também é integrante que é bom.
static void Main(string[] args)
{
const int precision = 10000;
foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
{
if ((int) (d*precision + .5)%precision == 0)
{
Console.WriteLine("{0} is an int", d);
}
}
}
e a saída é
2 is an int
1.99999999 is an int
2.00000001 is an int
Algo como isto
double d = 4.0;
int i = 4;
bool equal = d.CompareTo(i) == 0; // true
Você pode usar esta ??p>
bool IsInt(double x)
{
try
{
int y = Int16.Parse(x.ToString());
return true;
}
catch
{
return false;
}
}
Para lidar com a precisão do double ...
Math.Abs(d - Math.Floor(d)) <= double.Epsilon
Considere o seguinte caso em que um valor menos de double.Epsilon não comparar como zero.
// number of possible rounds
const int rounds = 1;
// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;
// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));
// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);
// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));