Les he explicado a mis alumnos que las pruebas equivalentes no son confiables para las variables flotantes, pero están bien para los enteros. El libro de texto que estoy usando dice que es más fácil de leer> y <que> = y <=. Estoy de acuerdo en cierta medida, pero en un bucle For? ¿No es más claro que el ciclo especifique los valores inicial y final?
¿Me estoy perdiendo algo sobre lo que el autor del libro de texto tiene razón?
Otro ejemplo es en pruebas de alcance como:
if score> 89 grade = 'A'
else if score> 79 grade = 'B' ...
¿Por qué no decir simplemente: si puntaje> = 90?
Respuestas:
En los lenguajes de programación con llaves y matrices basadas en cero , es costumbre escribir
for
bucles como este:Esto atraviesa todos los elementos de la matriz y es, con mucho, el caso más común. Evita el uso de
<=
o>=
.El único momento en que esto debería cambiar es cuando necesita omitir el primer o el último elemento, o atravesarlo en la dirección opuesta, o atravesarlo desde un punto de inicio diferente o un punto final diferente.
Para las colecciones, en idiomas que admiten iteradores, es más común ver esto:
Lo que evita las comparaciones por completo.
Si está buscando una regla dura y rápida sobre cuándo usar
<=
vs<
, no hay una; usa lo que mejor exprese tu intención. Si su código necesita expresar el concepto "Menor o igual a 55 millas por hora", entonces necesita decir que<=
no<
.Para responder a su pregunta sobre los rangos de calificaciones,
>= 90
tiene más sentido, porque 90 es el valor límite real, no 89.fuente
for
bucles como este. La forma defor
bucle que proporcioné aquí será reconocible instantáneamente para cualquier desarrollador con una mínima experiencia. Si desea una respuesta más específica basada en un escenario más específico, debe incluirla en su pregunta.No importa.
Pero por el bien del argumento, vamos a analizar las dos opciones:
a > b
vsa >= b
.¡Aférrate! ¡Esos no son equivalentes!
OK, entonces
a >= b -1
vsa > b
oa > b
vsa >= b +1
.Hm,
a >b
ya >= b
ambos se ven mejor quea >= b - 1
ya >= b +1
. ¿Qué son todos estos1
s de todos modos? Por lo tanto, argumentaría que cualquier beneficio de tener en>
lugar de>=
o viceversa se elimina al tener que sumar o restar1
s aleatorios .Pero, ¿y si es un número? ¿Es mejor decir
a > 7
oa >= 6
? Espera un segundo. ¿Estamos discutiendo seriamente si es mejor usar>
vs>=
e ignorar las variables codificadas? Entonces, realmente se convierte en una cuestión de sia > DAYS_OF_WEEK
es mejor quea >= DAYS_OF_WEEK_MINUS_ONE
... ¿o esa > NUMBER_OF_LEGS_IN_INSECT_PLUS_ONE
vsa >= NUMBER_OF_LEGS_IN_INSECT
? Y volvemos a sumar / restar1
s, solo que esta vez en nombres de variables. O tal vez debatir si es mejor usar umbral, límite, máximo.Y parece que no hay una regla general: depende de lo que se compara
Pero realmente, hay cosas mucho más importantes para mejorar en el código de uno y pautas mucho más objetivas y razonables (por ejemplo, límite de caracteres X por línea) que todavía tienen excepciones.
fuente
>
vs>=
o de si la discusión de>
vs>=
es significativa? aunque probablemente sea mejor evitar discutir esto: pComputacionalmente no hay diferencia en el costo cuando se usa
<
o se>
compara con<=
o>=
. Se calcula igual de rápido.Sin embargo, la mayoría de los bucles contarán desde 0 (porque muchos idiomas usan indexación 0 para sus matrices). Entonces, el bucle for canónico en esos idiomas es
hacer esto con un
<=
requeriría que agregue un -1 en algún lugar para evitar el error de off-byo
Por supuesto, si el lenguaje usa indexación basada en 1, entonces usaría <= como condición limitante.
La clave es que los valores expresados en la condición son los de la descripción del problema. Es más limpio leer
por un intervalo medio abierto que
y tengo que hacer los cálculos para saber que no hay un valor posible entre 19 y 20
fuente
for(markup = 5; markup <= MAX_MARKUP; ++markup)
. Cualquier otra cosa sería complicarlo demasiado.Yo diría que el punto no es si debes usar> o> =. El punto es usar lo que te permita escribir código expresivo.
Si encuentra que necesita sumar / restar uno, considere usar el otro operador. Creo que suceden cosas buenas cuando comienzas con un buen modelo de tu dominio. Entonces la lógica se escribe sola.
Esto es mucho más expresivo que
En otros casos, la otra forma es preferible:
Mucho mejor que
Por favor, disculpe la "obsesión primitiva". Obviamente, querrías usar un tipo de velocidad y dinero aquí respectivamente, pero los omití por brevedad. El punto es: use la versión que sea más concisa y que le permita enfocarse en el problema comercial que desea resolver.
fuente
Como señaló en su pregunta, las pruebas de igualdad en variables flotantes no son confiables.
Lo mismo es válido para
<=
y>=
.Sin embargo, no existe tal problema de confiabilidad para los tipos enteros. En mi opinión, la autora estaba expresando su opinión sobre cuál es más legible.
Si usted está o no de acuerdo con él es, por supuesto, su opinión.
fuente
<
o<=
basarme en lo que es más natural para el problema particular que estoy resolviendo. Como otros han señalado, en un bucle FOR<
tiene más sentido en lenguajes tipo C. Hay otros casos de uso que favorecen<=
. Use todas las herramientas a su disposición, cuando y donde sea apropiado.for (unsigned int i = n; i >= 0; i--)
ofor (unsigned int i = x; i <= y; i++)
siy
pasa a serUINT_MAX
. Oops, esos bucles para siempre.Cada una de las relaciones
<
,<=
,>=
,>
y también==
y!=
tienen sus casos de uso para comparar dos valores de coma flotante. Cada uno tiene un significado específico y se debe elegir el apropiado.Daré ejemplos de casos en los que desea exactamente este operador para cada uno de ellos. (Sin embargo, tenga en cuenta las NaN).
f
que toma un valor de punto flotante como entrada. Con el fin de acelerar sus cálculos, decide añadir una memoria caché de los valores más reciente calculada, es decir, una asignación de tabla de consultax
af(x)
. Realmente querrás usar==
para comparar los argumentos.x
? Probablemente quieras usarx != 0.0
.x
está en el intervalo de la unidad?(x >= 0.0) && (x < 1.0)
Es la condición correcta.d
de una matriz y desea saber si es positiva definida? No hay razón para usar otra cosa que no sead > 0.0
.alpha <= 1.0
.Las matemáticas de punto flotante (en general) no son exactas. Pero eso no significa que deba temerlo, tratarlo como magia, y ciertamente no siempre tratar dos cantidades de coma flotante iguales si están dentro
1.0E-10
. Hacerlo realmente romperá tus matemáticas y hará que sucedan cosas extrañas.x != 0.0
yy
es un valor finito de coma flotante,y / x
no necesita ser finito. Pero podría ser relevante saber siy / x
no es finito debido al desbordamiento o porque la operación no estaba matemáticamente bien definida para empezar.x
tenga que estar en el intervalo de la unidad [0, 1), estaría realmente molesto si disparara una falla de aserción cuando se llama conx == 0.0
ox == 1.0 - 1.0E-14
.1.0E-30
, no se gana nada. Todo lo que hizo fue aumentar la probabilidad de dar la respuesta incorrecta.alpha
podría verse afectado por los errores de redondeo y, poralpha <= 1.0
lo tanto, podría ser cierto a pesar de que el verdadero valor matemático para la expresiónalpha
se calculó podría haber sido realmente mayor que 1. Pero no hay nada que pueda hacer al respecto en este momento.Como siempre en la ingeniería de software, maneje los errores al nivel apropiado y hágalos solo una vez. Si agrega errores de redondeo en el orden de
1.0E-10
(este parece ser el valor mágico que usa la mayoría de la gente, no sé por qué) cada vez que compara cantidades de punto flotante, pronto encontrará errores en el orden de1.0E+10
...fuente
El tipo de condicional utilizado en un bucle puede limitar los tipos de optimizaciones que puede realizar un compilador, para bien o para mal. Por ejemplo, dado:
un compilador podría suponer que la condición anterior debería hacer que el ciclo salga después del enésimo paso a menos que n pueda ser 65535 y el ciclo pueda salir de alguna otra manera que no sea excediendo n. Si se aplican esas condiciones, el compilador debe generar un código que haga que el ciclo se ejecute hasta que algo más que la condición anterior lo haga salir.
Si el bucle se hubiera escrito como:
entonces un compilador podría asumir con seguridad que el ciclo nunca necesitaría ejecutarse más de n veces y, por lo tanto, podría generar un código más eficiente.
Tenga en cuenta que cualquier desbordamiento con tipos firmados puede tener consecuencias desagradables. Dado:
Un compilador podría reescribir eso como:
Tal bucle se comportaría de manera idéntica al original si no se produce un desbordamiento en los cálculos, pero podría ejecutarse para siempre, incluso en plataformas de hardware donde el desbordamiento de enteros normalmente tendría una semántica de ajuste consistente.
fuente