Hay un lenguaje estándar para la gama de comprobación con una sola instrucción de comparación.Dice así:
(unsigned)x - a <= (unsigned)b - a /* a <= x <= b */
(unsigned)x - a < (unsigned)b - a /* a <= x < b */
Como un ejemplo común (esta versión si isdigit
se garantiza que sea correcta por la norma):
(unsigned)ch - '0' < 10
Si el tipo de original es mayor que int
(por ejemplo long long
) luego deberá usar tipos sin firmar más grandes (por ejemplo, unsigned long long
). Si a
y b
son constantes o ya tiene tipo sin signo, o si conoce b-a
no se desbordará, se puede omitir el elenco de b
.
Para que este método funcione, naturalmente debe tener a<=b
y los tipos/valores debe ser tal que la expresión original (es decir a <= x && x <= b
o similar) se comporta matemáticamente correctamente. Por ejemplo, si x
fueron firmados y sin firmar b
, x<=b
podría evaluar en falso cuando x=-1
y b=UINT_MAX-1
. Siempre que sus tipos originales estén todos firmados o sean más pequeños que el tipo sin firmar al que se lanza, esto no es un problema.
En cuanto a cómo este "truco" funciona, es puramente determinar, después de la reducción de módulo UINT_MAX+1
, si x-a
se encuentra en el rango de 0 a b-a
.
En su caso, creo que el siguiente debería funcionar bien:
(unsigned)i + threshold > 2U * threshold;
Si threshold
no cambia entre las iteraciones del bucle, el compilador probablemente puede mantener tanto threshold
y 2U*threshold
en los registros.
Hablando de optimizaciones, un buen compilador debe optimizar su prueba original gama de usar la aritmética sin signo donde se sabe que se cumplan las restricciones. Sospecho que muchos lo hacen con a
y b
constante, pero tal vez no con expresiones más complejas. Incluso si el compilador puede optimizar, sin embargo, el lenguaje (unsigned)x-a<b-a
sigue siendo de gran utilidad en las macros en las que desea asegurarse de que x
se evalúa exactamente una vez.
dices "ambos" pero hay tres variables. – McKay
no puedo recordar si esto funciona con seguridad, pero intento 'if ((unsigned int) i> threshold)' – zdav
@zdav Definitivamente no funciona para la mayoría de los compiladores. Tales conversiones están definidas al menos por implementación y generalmente te dan un complemento de 2. –