No, pero sí, pero tal vez, pero tal vez a la inversa, pero no.
Como la gente ya ha señalado, (suponiendo un lenguaje donde la suma es asociativa a la izquierda, como C, C ++, C # o Java) la expresión ((1 + 2) + 3)
es exactamente equivalente a1 + 2 + 3
. Son diferentes formas de escribir algo en el código fuente, que tendrían un efecto cero en el código de máquina resultante o el código de bytes.
De cualquier manera, el resultado será una instrucción para, por ejemplo, agregar dos registros y luego agregar un tercero, o tomar dos valores de una pila, agregarlo, empujarlo hacia atrás, luego tomarlo y otro y agregarlos, o agregar tres registros en una sola operación, o alguna otra forma de sumar tres números dependiendo de lo que sea más sensato en el siguiente nivel (el código de máquina o el código de byte). En el caso del código de bytes, eso a su vez probablemente sufrirá una reestructuración similar, por ejemplo, el equivalente IL de esto (que sería una serie de cargas en una pila, y apareciendo pares para agregar y luego retrasar el resultado) no daría como resultado una copia directa de esa lógica a nivel de código de máquina, sino algo más sensible para la máquina en cuestión.
Pero hay algo más en tu pregunta.
En el caso de cualquier compilador sano de C, C ++, Java o C #, esperaría que el resultado de ambas afirmaciones tenga exactamente los mismos resultados que:
int a = 6;
¿Por qué el código resultante debería perder tiempo haciendo cálculos matemáticos en literales? Ningún cambio en el estado del programa detendrá el resultado de 1 + 2 + 3
ser 6
, así que eso es lo que debería ir en el código que se ejecuta. De hecho, tal vez ni siquiera eso (dependiendo de lo que hagas con ese 6, tal vez podamos tirar todo por la borda; e incluso C # con su filosofía de "no optimizar en gran medida, ya que el jitter optimizará esto de todos modos" producirá el equivalente int a = 6
o simplemente tirar todo como innecesario).
Sin embargo, esto nos lleva a una posible extensión de su pregunta. Considera lo siguiente:
int a = (b - 2) / 2;
/* or */
int a = (b / 2)--;
y
int c;
if(d < 100)
c = 0;
else
c = d * 31;
/* or */
int c = d < 100 ? 0 : d * 32 - d
/* or */
int c = d < 100 && d * 32 - d;
/* or */
int c = (d < 100) * (d * 32 - d);
(Tenga en cuenta que estos dos últimos ejemplos no son válidos en C #, mientras que todo lo demás aquí sí lo es, y son válidos en C, C ++ y Java).
Aquí nuevamente tenemos un código exactamente equivalente en términos de salida. Como no son expresiones constantes, no se calcularán en tiempo de compilación. Es posible que una forma sea más rápida que otra. ¿Cual es mas rápido? Eso dependería del procesador y quizás de algunas diferencias de estado bastante arbitrarias (particularmente porque si uno es más rápido, no es probable que sea mucho más rápido).
Y no están completamente ajenos a su pregunta, ya que se refieren principalmente a las diferencias en el orden en que se hace algo conceptualmente .
En cada uno de ellos, hay una razón para sospechar que uno puede ser más rápido que el otro. Los decrementos individuales pueden tener una instrucción especializada, por lo que (b / 2)--
podrían ser más rápidos que (b - 2) / 2
. d * 32
tal vez podría producirse más rápido convirtiéndolo en d << 5
algo d * 32 - d
más rápido que d * 31
. Las diferencias entre los dos últimos son particularmente interesantes; uno permite omitir parte del procesamiento en algunos casos, pero el otro evita la posibilidad de una predicción errónea de la rama.
Entonces, esto nos deja con dos preguntas: 1. ¿Una es realmente más rápida que la otra? 2. ¿Un compilador convertirá lo más lento en lo más rápido?
Y la respuesta es 1. Depende. 2. Quizás.
O para expandirse, depende porque depende del procesador en cuestión. Ciertamente, han existido procesadores donde el equivalente de código de máquina ingenuo de uno sería más rápido que el equivalente de código de máquina ingenuo del otro. A lo largo de la historia de la computación electrónica, tampoco ha habido uno que sea siempre más rápido (el elemento de predicción errónea de la rama en particular no era relevante para muchos cuando las CPU no canalizadas eran más comunes).
Y tal vez, porque hay un montón de optimizaciones diferentes que harán los compiladores (y las fluctuaciones, y los motores de script), y aunque algunos pueden ser obligatorios en ciertos casos, generalmente podremos encontrar algunas piezas de código lógicamente equivalente que Incluso el compilador más ingenuo tiene exactamente los mismos resultados y algunas piezas de código lógicamente equivalente donde incluso el más sofisticado produce código más rápido para uno que para el otro (incluso si tenemos que escribir algo totalmente patológico solo para demostrar nuestro punto).
Puede parecer una preocupación de optimización muy pequeña,
No. Incluso con diferencias más complicadas que las que presento aquí, parece una preocupación absolutamente minuciosa que no tiene nada que ver con la optimización. En todo caso, es una cuestión de pesimismo, ya que sospecha que lo más difícil de leer ((1 + 2) + 3
podría ser más lento que lo más fácil de leer 1 + 2 + 3
.
pero elegir C ++ sobre C # / Java / ... se trata de optimizaciones (en mi humilde opinión).
Si de eso se trata realmente la elección de C ++ sobre C # o Java, diría que la gente debería grabar su copia de Stroustrup e ISO / IEC 14882 y liberar el espacio de su compilador de C ++ para dejar espacio para algunos MP3 más o algo así.
Estos idiomas tienen diferentes ventajas entre sí.
Una de ellas es que C ++ sigue siendo generalmente más rápido y más liviano en el uso de la memoria. Sí, hay ejemplos en los que C # y / o Java son más rápidos y / o tienen un mejor uso de la memoria de la aplicación, y estos se están volviendo más comunes a medida que las tecnologías involucradas mejoran, pero aún podemos esperar que el programa promedio escrito en C ++ sea un ejecutable más pequeño que hace su trabajo más rápido y usa menos memoria que el equivalente en cualquiera de esos dos idiomas.
Esto no es optimización.
La optimización a veces se usa para significar "hacer que las cosas vayan más rápido". Es comprensible, porque a menudo, cuando realmente estamos hablando de "optimización", en realidad estamos hablando de hacer que las cosas vayan más rápido, por lo que uno se ha convertido en una abreviatura para el otro y admito que mal uso la palabra de esa manera.
La palabra correcta para "hacer que las cosas vayan más rápido" no es optimización . La palabra correcta aquí es mejora . Si realiza un cambio en un programa y la única diferencia significativa es que ahora es más rápido, no está optimizado de ninguna manera, es simplemente mejor.
La optimización es cuando hacemos una mejora con respecto a un aspecto particular y / o caso particular. Ejemplos comunes son:
- Ahora es más rápido para un caso de uso, pero más lento para otro.
- Ahora es más rápido, pero usa más memoria.
- Ahora es más ligero en la memoria, pero más lento.
- Ahora es más rápido, pero más difícil de mantener.
- Ahora es más fácil de mantener, pero más lento.
Tales casos estarían justificados si, por ejemplo:
- El caso de uso más rápido es más común o se ve obstaculizado más severamente para empezar.
- El programa era inaceptablemente lento, y tenemos mucha RAM libre.
- El programa se estaba deteniendo porque usaba tanta RAM que pasaba más tiempo intercambiando que ejecutando su procesamiento súper rápido.
- El programa era inaceptablemente lento y el código más difícil de entender está bien documentado y es relativamente estable.
- El programa todavía es aceptablemente rápido, y la base de código más comprensible es más barata de mantener y permite realizar otras mejoras más fácilmente.
Pero, estos casos tampoco estarían justificados en otros escenarios: el código no se ha mejorado por una medida de calidad absoluta infalible, se ha mejorado en un aspecto particular que lo hace más adecuado para un uso particular; optimizado
Y la elección del lenguaje tiene un efecto aquí, porque la velocidad, el uso de la memoria y la legibilidad pueden verse afectados por él, pero también la compatibilidad con otros sistemas, la disponibilidad de bibliotecas, la disponibilidad de tiempos de ejecución, la madurez de esos tiempos de ejecución en un sistema operativo dado (Por mis pecados, de alguna manera terminé teniendo Linux y Android como mis sistemas operativos favoritos y C # como mi lenguaje favorito, y aunque Mono es genial, pero todavía me encuentro con este bastante).
Decir que "elegir C ++ sobre C # / Java / ... tiene que ver con optimizaciones" solo tiene sentido si cree que C ++ realmente apesta, porque la optimización se trata de "mejor a pesar de ..." no "mejor". Si crees que C ++ es mejor a pesar de sí mismo, entonces lo último que necesitas es preocuparte por esas microopciones posibles tan pequeñas. De hecho, probablemente sea mejor que lo abandones; ¡los hackers felices también son una calidad para optimizar!
Sin embargo, si se inclina a decir "Me encanta C ++, y una de las cosas que me encanta es exprimir ciclos adicionales", entonces ese es un asunto diferente. Sigue siendo un caso que las microopciones solo valen la pena si pueden ser un hábito reflexivo (es decir, la forma en que tiende a codificar de forma natural será más rápido que más lento). De lo contrario, ni siquiera son optimización prematura, son pesimismo prematuro que empeoran las cosas.