2010-02-11 23 views
5

Al comparar por igualdad, ¿está bien usar ==?Al comparar por igualdad, ¿está bien usar `==`?

Por ejemplo:

int a = 3; 
int b = 4; 

Si la comprobación de la igualdad se debe utilizar:

if (a == b) 
{ 
    . . . 
} 

¿Sería se utilizaron el cambio de situación si los números de punto flotante?

+0

para número entero == es suficiente – malay

+0

Y el código con == es más limpio y más legible. – Igor

+8

La segunda prueba es en realidad una prueba de desigualdad. – rlbond

Respuesta

15

'==' es perfectamente bueno para valores enteros.

Usted debe no comparar carrozas para la igualdad; utilice un enfoque de tolerancia:

if (fabs(a - b) < tolerance) 
{ 
    // a and b are equal to within tolerance 
} 
+0

Por favor, use fabs! comparar con abs convierte los argumentos a int primero ... lo que equivale a comparaciones muy inexactas. –

+3

@Michael 'abs' está sobrecargado para tipos de punto flotante en' cmath', no hay problema en el código de Mitch. – AraK

+4

Uno necesita usar std :: abs, porque solo eso está sobrecargado. La función C :: abs no es. Siempre indicaba explícitamente el espacio de nombres para evitar errores difíciles de depurar en caso de que escoja accidentalmente la función C no sobrecargada. – Tronic

4

Re puntos flotantes: sí. No use == para flotadores (o sepa EXACTAMENTE lo que está haciendo si lo hace). utilizar bien algo así como

if (fabs(a - b) < SOME_DELTA) { 
    ... 
} 

EDIT: se ha cambiado abs()() a FABS

+0

Nunca usaría == para comparar flotadores. –

+0

Por favor, use fabs! comparar con abs convierte los argumentos a int primero ... lo que equivale a comparaciones muy inexactas. –

+1

@Mitch Wheat: Es por eso que Frank Shearar mencionó que debes saber lo que haces. Si lo haces, usar == está bien. Vea Goldbergs con clase "Lo que todo científico de la computación debe saber sobre matemática de punto flotante" (http://docs.sun.com/source/806-3568/ncg_goldberg.html) –

1

bien la comparación de enteros, el uso ==. El uso de "<" y ">" al mismo tiempo para verificar la igualdad en un int resulta en un código más lento porque toma dos comparaciones en lugar de una, tomando el doble de tiempo. (aunque probablemente el compilador se lo arreglará, pero no debería acostumbrarse a escribir código incorrecto).

Recuerde, la optimización temprana es mala, pero el código temprano ineficiente es igual de malo.

EDIT: Se han solucionado algunos Inglés ...

+0

Downvoters se preocupan por explicar lo que dije mal? – speeder

+0

Ok, ¿así que tenemos gente que venció a otros para promocionar sus amigos? Tengo 2 votos negativos y ninguna explicación, si eres un crítico real, deberías ver que soy novato, y debes saber que no tengo idea de lo que hice mal, pero si no eres un crítico real, no debería andar arrojando votos al azar al azar. – speeder

+1

No he votado negativamente, pero la afirmación de dos comparaciones que producen código más lento es muy falsa, ya que los compiladores (como usted dice) lo optimizan de todos modos. – Tronic

2

En muchas clases, operator== se implementa típicamente como (!(a < b || b < a)), por lo que debe seguir adelante y utilizar ==. Excepto por carrozas, como dijo Mitch Wheat arriba.

+1

Me sorprende que un solo operador se implemente en términos de 3 operadores en muchos casos. Y si se implementa típicamente como se indica arriba, explica en gran parte por qué el universo está tan desordenado: 'a Duncan

+0

Nunca he visto un compilador que genere código para '==' usar nada que no sea una sola instrucción de comparación. Si entiendo correctamente, ¿estás diciendo que hace dos comparaciones y no verifica la "igualdad" sino un par de menos? – wallyk

+1

rlbond no está hablando de tipos incorporados, sino de clases de usuarios. Escribir operador == de esa manera es típico, porque el operador de comparación "estándar" en C++ es el operador <, aunque solo sea porque eso es lo que usa el STL. Entonces, escribir otros operadores de comparación en términos de operador Gorpik

1

Para enteros, == hace justo lo que esperas. Si son iguales, son iguales.

Para carrozas, es otra historia. Las operaciones producen resultados imprecisos y se acumulan errores. Debes ser un poco confuso cuando se trata de números. Yo uso

if (std::abs(a - b) 
    < std::abs(a) * (std::numeric_limits<float_t>::epsilon() * error_margin)) 

donde float_t es un typedef; esto me da la mayor precisión posible (suponiendo que el error_margin se calculó correctamente) y permite un ajuste fácil a otro tipo.

Además, algunos valores de punto flotante no son números: hay infinito, menos infinito y, por supuesto, no es un número. == hace cosas divertidas con aquellos. Infinito equivale a infinito, pero no un número no es igual a un no número.

¡Finalmente, hay cero positivo y negativo, que son distintos pero iguales el uno al otro! Para separarlos, debe hacer algo como verificar si el inverso es infinito positivo o negativo. (Solo asegúrese de que no obtendrá una excepción de división por cero).)

Por lo tanto, a menos que tenga una pregunta más específica, espero que lo maneja ...

+0

No es una buena idea si a es negativo. try std :: abs (a-b) <(std :: abs (a) + std :: abs (b)) * .... –

+0

@Michael: Gracias, corregido. No es necesario agregarlos en el RHS, ya que la comparación sería falsa si hacía una diferencia. La diferencia entre épsilon * (a + a) y épsilon * (a + b) es menor que la precisión de a-b, o bien error_margin debe elegirse lo suficientemente bajo para que la comparación falle. Quizás agregar a + b es importante si está filtrando más de la mitad de los bits de mantisa ... en cualquier caso, se requiere algún análisis del cálculo real. – Potatoswatter

+0

El problema que tengo con su método de comparación actualizado es que no es simétrico. es decir, puede comparar (a, b)! = Comparar (b, a) cuando b-a está cerca de la tolerancia escalada. No me gusta esa posibilidad. –

2

Haciendo < y> comparaciones en realidad no le ayudará con errores de redondeo. Use la solución dada por Mark Shearar. Sin embargo, las comparaciones directas de igualdad para carrozas no siempre son malas. Puede usarlos si algún valor específico (por ejemplo, 0.0 o 1.0) se asigna directamente a una variable, para verificar si la variable todavía tiene ese valor. Solo después de los cálculos, los errores de redondeo arruinan las verificaciones de igualdad.

Observe que al comparar un valor NaN con cualquier cosa (también otro NaN) con <,>, < =,> = o == devuelve falso. ! = devuelve verdadero.

+0

Mark Shearar no participó en este hilo –

+0

@phresnel: si quieres decir que él confundió a "Mark" con "Frank", OK, deja que el chico viva ... – Gorpik

+0

@Gorpik: por supuesto, esto no fue un insulto o algo así :) –

Cuestiones relacionadas