¿Cuál es más rápido entre if (n / 10 == 0) y if (n> = 0 && n <= 9) en C ++?

Mientras que otros tienen razón en que la división es una operación muy lenta (ya que esencialmente el algoritmo de división es casi el mismo que usted conoce de la escuela y no se “paraleliza” bien) también están equivocados porque en este caso particular no hay división involucrada . Los compiladores son lo suficientemente inteligentes como para reemplazar la división (y el módulo) con la multiplicación siempre que el segundo operando sea una constante. Probablemente podría llegar a esta optimización recordando que la división por x es casi lo mismo que la multiplicación por 1 / x. Por supuesto, en realidad no podemos usar números reales, solo sus aproximaciones binarias finitas, por lo que solo debe tomar los 32 bits más significativos de 1 / x y codificarlos en tiempo de compilación, como por ejemplo, y. Luego, en lugar de x / n, puede usar n • y >> 32, que es una buena aproximación, pero a menudo requiere una verificación adicional para el error de redondeo; por ejemplo, puede comparar n-result • x <x, pero los compiladores conocen mejores trucos que eso . En mi opinión, sin mirar el código de ensamblaje generado por su compilador, es imposible saber qué se hace realmente en cada una de estas implementaciones.
La pregunta sobre la velocidad también es algo que uno no puede resolver sin probar en el mundo moderno y cuanto antes se dé cuenta de esto, será mejor programador, ya que hay más problemas causados ​​por el culto de la carga y el juicio erróneo que por el código subóptimo.
Mi intuición es que dos ramas condicionales pueden disparar la predicción anticipada del procesador y ralentizar la canalización, pero no estoy seguro de si es probable en su escenario realizar dos saltos y cómo el compilador organizará las rutas predeterminadas para estas dos condiciones .
Pruébalo:)

Dicho todo esto, considere este programa:

int main(int argc,char * args[]){
if(argc/10){
return 1;
}else{
return 0;
}
}

y compilar mira el ensamblaje:

g ++ –save-temps test.cpp
prueba de gato.
.archivo “test.cpp”
.texto
.globl principal
.type main, @function
principal:
.LFB0:
.cfi_startproc
pushl% ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl% esp,% ebp
.cfi_def_cfa_register 5
movl 8 (% ebp),% eax
addl $ 9,% eax
cmpl $ 18,% eax
jbe .L2
movl $ 1,% eax
jmp .L3
.L2:
movl $ 0,% eax
.L3:
popl% ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
jubilado
.cfi_endproc
.LFE0:
.size main,.-main
.ident “GCC: (Debian 4.7.2-5) 4.7.2″
.section .note.GNU-stack, “”, @ progbits

Observe que no hay operación de división en este ensamblado (por lo que otros están equivocados).
Tenga en cuenta que no hay multiplicación (así que me equivoqué).
Tenga en cuenta que el ensamblaje es algo totalmente diferente al código cpp.
Y esta, mi amigo, es la lección más importante que puedes obtener aquí: aprender a ser abierto, aprender a no confiar en tus sentimientos, aprender a profundizar y verificar los hechos 🙂

Por cierto, ¿qué hace el compilador en este caso? Parece que reemplazó n / 10 con n <= 9.

No son equivalentes.

(n / 10 == 0) también es cierto en -1, -2, -3,…, -9, mientras que (n> = 0 && n <= 9) no lo es. Suponiendo que n es un int. De lo contrario, son incluso "menos equivalentes".

Si desea ignorar los números negativos, también podría escribir (n <= 9).

Si aún desea comparar ambos, estoy bastante seguro de que la segunda condición es mucho más rápida ya que la primera implica división, que es una operación pesada a menos que sea por una potencia de 2, en cuyo caso probablemente se compilaría en un cambio de bits que es bastante rápido.

Es poco probable que el código sea tan crítico que haya algo para elegir entre ellos.
La forma algebraica n / 10 es propensa a errores, como lo demuestran las otras respuestas, y también es menos obvio para que otra persona depure o modifique el código para nuevos requisitos. por ejemplo, ¿cómo cambiaría la forma algebraica al nuevo requisito 1 <= n <= 9

En el primer caso, cada vez que n se divide primero por 10 y luego se compara con 0. Por lo tanto, se realizan dos operaciones cada vez. Pero en el siguiente caso, el número se compara directamente. Entonces, obviamente, es más rápido que el primero. Pero prácticamente la diferencia no se puede experimentar a menos que la instrucción if se ejecute muchas veces en un bucle.

Bueno, no hacen lo mismo para los números negativos.

Pero, en general, la división es más lenta que todo lo demás, por lo que elegiría la segunda forma.

More Interesting

¿Cuál es una explicación intuitiva de por qué hay números primos infinitos?

¿Cuántos pares ordenados [matemática] (x, y) [/ matemática] existen (donde [matemática] x, y [/ matemática] son ​​números primos), de modo que [matemática] x ^ 2 – 2y ^ 2 = 1 [/ matemáticas]?

Cómo demostrar que para cada [matemática] a \ lt b, [/ matemática] [matemática] a, b \ in \ mathbb {N} [/ matemática] 1) [matemática] 3 ^ {2 ^ a} +1 [ / math] divide [math] 3 ^ {2 ^ b} -1 [/ math] 2) Si [math] d \ gt 2, d \ in \ mathbb {N} [/ math], entonces [math] d [ / math] no divide tanto [math] 3 ^ {2 ^ a} + 1 [/ math] como [math] 3 ^ {2 ^ b} -1 [/ math]

¿Existe un método matemático para encontrar x donde x ^ x = y, y representando un número entero positivo?

¿Qué temas importantes de la teoría de números debería saber todo programador?

¿Cuáles son las (soluciones no triviales) de la siguiente ecuación entera [matemática] 2 x ^ 3 + y ^ 2 = z ^ k [/ matemática] donde [matemática] (x, y, z) [/ matemática] son ​​enteros distintos de cero y [matemáticas] k [/ matemáticas] es un número entero positivo mayor que tres?

¿De qué manera es más rápido generar dos números aleatorios 1 y -1 en la programación?

La ecuación [matemáticas] x ^ 2 + kx + 8 = k [/ matemáticas] no tiene soluciones reales para x. ¿Cuál es el mayor valor entero posible para k?

¿Es [matemática] 10 ^ n + 1 [/ matemática] siempre compuesta cuando [matemática] n [/ matemática] es un número entero mayor que dos?

Deje [math] p [/ math] ser un número primo impar y [math] \ zeta = \ zeta_p = \ cos \ left (\ frac {2 \ pi} {p} \ right) + i \ sin \ left (\ frac {2 \ pi} {p} \ right) [/ math]. ¿Cómo haces lo siguiente?