Pregunta

Este código funciona (C # 3)

double d;
if(d == (double)(int)d) ...;
  1. ¿Hay una mejor manera de hacer esto?
  2. Por razones extrañas, quiero evitar el doble lanzamiento; ¿Qué buenas maneras existen aparte de esto? (incluso si no son tan buenos)

Nota: Varias personas señalaron el punto (importante) de que == a menudo es problemático volver a clasificar el punto flotante. En estos casos, espero valores en el rango de 0 a unos pocos cientos y se supone que son enteros (los no ints son errores), por lo que si esos puntos & Quot; no deberían & Quot; ser un problema para mí.

¿Fue útil?

Solución

d == Math.Floor(d)

hace lo mismo en otras palabras.

NB: Espero que sea consciente de que debe tener mucho cuidado al hacer este tipo de cosas; los flotantes / dobles acumularán fácilmente errores minúsculos que hacen que las comparaciones exactas (como esta) fallen sin razón aparente.

Otros consejos

Si su doble es el resultado de otro cálculo, probablemente desee algo como:

d == Math.Floor(d + 0.00001);

De esa manera, si ha habido un pequeño error de redondeo, aún coincidirá.

Creo que esto funcionaría:

if (d % 1 == 0) {
  //...
}

No puedo responder la parte específica de C # de la pregunta, pero debo señalar que probablemente se está perdiendo un problema genérico con números de coma flotante.

Generalmente, el número entero no está bien definido en las carrozas. Por la misma razón que la igualdad no está bien definida en las carrozas. Los cálculos de punto flotante normalmente incluyen errores de redondeo y representación.

Por ejemplo, 1.1 + 0.6 != 1.7.

Sí, así es como funcionan los números de coma flotante.

Aquí, 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16.

Hablando estrictamente, lo más parecido a la comparación de igualdad que puede hacer con flotadores es compararlos con la precisión elegida .

Si esto no es suficiente, debe trabajar con una representación de número decimal, con una representación de número de coma flotante con rango de error incorporado o con cálculos simbólicos.

Si solo va a convertirlo, la respuesta de Mike F / Khoth es buena, pero no responde a su pregunta. Si realmente va a probar, y es realmente importante, le recomiendo que implemente algo que incluya un margen de error.

Por ejemplo, si está considerando el dinero y desea probar incluso cantidades en dólares, podría decir (siguiendo el patrón de Khoth):

if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)

En otras palabras, tome el valor absoluto de la diferencia del valor y su representación entera y asegúrese de que sea pequeño.

No necesitas el extra (doble) allí. Esto funciona:

if (d == (int)d) {
 //...
}

Usar Math.Truncate ()

Una prueba simple como 'x == floor (x)' está matemáticamente asegurada para funcionar correctamente, para cualquier número FP de precisión fija.

Todas las codificaciones legales de FP de precisión fija representan números reales distintos, por lo que para cada número entero x, existe como máximo una codificación FP de precisión fija que coincide exactamente con ella.

Por lo tanto, para cada número entero x que PUEDE representarse de tal manera, tenemos x == floor (x) necesariamente, ya que floor (x) por definición devuelve el número FP más grande y tal que y < = x e y representa un número entero; entonces el piso (x) debe devolver x.

Esto le permitirá elegir qué precisión está buscando, más o menos la mitad de un tic, para tener en cuenta la deriva de coma flotante. La comparación también es integral, lo cual es bueno.

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

y el resultado es

2 is an int
1.99999999 is an int
2.00000001 is an int

Algo como esto

double d = 4.0;
int i = 4;

bool equal = d.CompareTo(i) == 0; // true

¿Podría usar esto?

    bool IsInt(double x)
    {
        try
        {
            int y = Int16.Parse(x.ToString());
            return true;
        }
        catch 
        {
            return false;
        }
    }

Para manejar la precisión del doble ...

Math.Abs(d - Math.Floor(d)) <= double.Epsilon

Considere el siguiente caso donde un valor menor que el doble. Epilon no se compara como cero.

// 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"));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top