Não, mas sim, mas talvez, mas talvez o contrário, mas não.
Como as pessoas já apontaram, (assumindo uma linguagem em que a adição é associativa à esquerda, como C, C ++, C # ou Java), a expressão ((1 + 2) + 3)
é exatamente equivalente a 1 + 2 + 3
. São maneiras diferentes de escrever algo no código-fonte, que teria efeito nulo no código de máquina ou no código de bytes resultante.
De qualquer maneira, o resultado será uma instrução para, por exemplo, adicionar dois registradores e, em seguida, adicionar um terceiro, ou pegar dois valores de uma pilha, adicioná-los, empurrá-los para trás, depois pegá-los e outro e adicioná-los ou adicionar três registradores em uma única operação ou outra maneira de somar três números, dependendo do que for mais sensato no próximo nível (o código da máquina ou o código de bytes). No caso do código de bytes, que por sua vez provavelmente passará por uma reestruturação semelhante, por exemplo, o equivalente a IL disso (que seria uma série de cargas para uma pilha e popping pares para adicionar e depois empurrar o resultado). não resultaria em uma cópia direta dessa lógica no nível do código da máquina, mas em algo mais sensato para a máquina em questão.
Mas há algo mais na sua pergunta.
No caso de qualquer compilador C, C ++, Java ou C #, esperaria que o resultado de ambas as instruções fornecidas tivesse exatamente os mesmos resultados que:
int a = 6;
Por que o código resultante deve perder tempo fazendo matemática em literais? Nenhuma alteração para o estado do programa irá parar o resultado de 1 + 2 + 3
estar 6
, e é isso que deve ir para o código que está sendo executado. De fato, talvez nem isso (dependendo do que você faça com esse 6, talvez possamos jogar tudo fora; e até mesmo o C # com a filosofia de "não otimize fortemente, pois o jitter irá otimizar isso de qualquer maneira" produzirá o equivalente int a = 6
ou simplesmente jogar tudo fora como desnecessário).
Isso nos leva a uma possível extensão de sua pergunta. Considere o seguinte:
int a = (b - 2) / 2;
/* or */
int a = (b / 2)--;
e
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);
(Observe, esses dois últimos exemplos não são válidos em C #, enquanto tudo o resto é válido e são válidos em C, C ++ e Java.)
Aqui, novamente, temos código exatamente equivalente em termos de saída. Como não são expressões constantes, não serão calculadas em tempo de compilação. É possível que um formulário seja mais rápido que outro. O que é mais rápido? Isso dependeria do processador e talvez de algumas diferenças arbitrárias de estado (principalmente porque se um é mais rápido, não é provável que seja muito mais rápido).
E elas não estão totalmente relacionadas à sua pergunta, pois tratam principalmente de diferenças na ordem em que algo é feito conceitualmente .
Em cada um deles, há uma razão para suspeitar que um pode ser mais rápido que o outro. Os decréscimos únicos podem ter uma instrução especializada; portanto, (b / 2)--
podem ser mais rápidos que (b - 2) / 2
. d * 32
talvez pudesse ser produzida mais rapidamente, transformando-a d << 5
assim tornando d * 32 - d
mais rápido do que d * 31
. As diferenças entre os dois últimos são particularmente interessantes; um permite que algum processamento seja ignorado em alguns casos, mas o outro evita a possibilidade de predição incorreta de ramificação.
Então, isso nos deixa com duas perguntas: 1. Uma é realmente mais rápida que a outra? 2. Um compilador converterá o mais lento no mais rápido?
E a resposta é 1. Depende. 2. Talvez.
Ou, para expandir, depende porque depende do processador em questão. Certamente existiam processadores em que o equivalente ingênuo do código de máquina de um seria mais rápido que o equivalente ingênuo do código de máquina do outro. Ao longo da história da computação eletrônica, também não houve uma que fosse sempre mais rápida (o elemento de predição incorreta de ramificação em particular não era relevante para muitos quando as CPUs sem pipeline eram mais comuns).
E talvez, porque existem várias otimizações diferentes que os compiladores (e nervosismo e mecanismos de script) farão, e embora alguns possam ser obrigatórios em certos casos, geralmente seremos capazes de encontrar algumas partes de código logicamente equivalente que até o compilador mais ingênuo tem exatamente os mesmos resultados e algumas partes de código logicamente equivalente, onde até o mais sofisticado produz código mais rápido para um do que para o outro (mesmo que tenhamos que escrever algo totalmente patológico apenas para provar nosso argumento).
Pode parecer uma preocupação muito pequena de otimização,
Não. Mesmo com diferenças mais complicadas do que as que dou aqui, parece uma preocupação absolutamente minuciosa que não tem nada a ver com otimização. Na verdade, é uma questão de pessimização, pois você suspeita que o mais difícil de ler ((1 + 2) + 3
pode ser mais lento do que o mais fácil de ler 1 + 2 + 3
.
mas escolher C ++ em C # / Java / ... tem tudo a ver com otimizações (IMHO).
Se realmente era assim que escolher C ++ sobre C # ou Java era "tudo", eu diria que as pessoas deveriam gravar sua cópia do Stroustrup e da ISO / IEC 14882 e liberar o espaço do compilador C ++ para deixar espaço para mais alguns MP3s ou algo assim.
Esses idiomas têm vantagens diferentes entre si.
Uma delas é que o C ++ ainda é geralmente mais rápido e mais leve no uso da memória. Sim, existem exemplos em que C # e / ou Java são mais rápidos e / ou têm melhor uso da memória durante a vida útil do aplicativo, e estes estão se tornando mais comuns à medida que as tecnologias envolvidas melhoram, mas ainda podemos esperar que o programa médio escrito em C ++ seja um executável menor que faz seu trabalho mais rápido e usa menos memória que o equivalente em um desses dois idiomas.
Isso não é otimização.
Às vezes, otimização é usada para significar "tornar as coisas mais rápidas". É compreensível, porque, muitas vezes, quando realmente estamos falando sobre "otimização", estamos realmente falando sobre tornar as coisas mais rápidas e, portanto, uma se tornou uma abreviação para a outra e eu admito que eu uso mal a palavra dessa maneira.
A palavra correta para "acelerar as coisas" não é otimização . A palavra correta aqui é melhoria . Se você fizer uma alteração em um programa e a única diferença significativa é que agora ele é mais rápido, não é otimizado de forma alguma, é apenas melhor.
Otimização é quando fazemos uma melhoria em relação a um aspecto particular e / ou caso particular. Exemplos comuns são:
- Agora é mais rápido para um caso de uso, mas mais lento para outro.
- Agora é mais rápido, mas usa mais memória.
- Agora está mais claro na memória, mas mais lento.
- Agora é mais rápido, mas mais difícil de manter.
- Agora é mais fácil de manter, mas mais lento.
Tais casos seriam justificados se, por exemplo:
- O caso de uso mais rápido é mais comum ou mais dificultado para começar.
- O programa era inaceitavelmente lento e temos muita memória livre.
- O programa estava paralisado porque usava tanta RAM que passava mais tempo trocando do que executando seu processamento super-rápido.
- O programa era inaceitavelmente lento e o código mais difícil de entender é bem documentado e relativamente estável.
- O programa ainda é aceitável e rápido, e a base de código mais compreensível é mais barata de manter e permite que outras melhorias sejam feitas com mais facilidade.
Porém, esses casos também não seriam justificados em outros cenários: o código não foi aprimorado por uma medida infalível absoluta de qualidade, foi aprimorado em um aspecto específico que o torna mais adequado para um uso específico; otimizado.
E a escolha do idioma tem efeito aqui, porque a velocidade, o uso da memória e a legibilidade podem ser afetados por ele, mas também a compatibilidade com outros sistemas, disponibilidade de bibliotecas, disponibilidade de tempos de execução, maturidade desses tempos de execução em um determinado sistema operacional. (pelos meus pecados, de alguma forma, acabei tendo Linux e Android como meus sistemas operacionais favoritos e C # como meu idioma favorito, e enquanto o Mono é ótimo, mas ainda me deparei com isso bastante).
Dizer "escolher C ++ em C # / Java / ... é tudo sobre otimizações" só faz sentido se você acha que C ++ realmente é péssimo, porque a otimização é "melhor apesar de ..." não "melhor". Se você acha que o C ++ é melhor, apesar de tudo, a última coisa que você precisa é se preocupar com possíveis microopções tão minuciosas. De fato, é melhor você provavelmente abandoná-lo; hackers felizes também são uma qualidade para otimizar!
Se, no entanto, você está inclinado a dizer "Eu amo C ++, e uma das coisas que eu amo sobre isso é extrair ciclos extras", então isso é uma questão diferente. Ainda é um caso em que as micro-opções valem a pena se puderem ser um hábito reflexivo (ou seja, a maneira como você tende a codificar naturalmente será mais rápida com mais frequência do que com a velocidade mais lenta). Caso contrário, nem sequer são otimizações prematuras, são pessimizações prematuras que apenas pioram as coisas.