Por definição, no Pascal a avaliação sempre é completa (O Turbo Pascal tinha uma opção para mudar este comportamento.), e no C é incompleta.
O que é isto? Quais são as consequências? Como melhor aproveitar isto.
No Pascal as avaliações de expressões lógicas são completas, i.e., todas as partes são avaliadas, não importando se no meio delas já é possível obter o resultado final ou não. No exemplo abaixo, e a foi maior ou igual a b - portanto a primeira comparação é falsa, o que implica que o resultado do and das duas expressões é falso - b ainda será comparado com c.
if a < b and b < c then
begin
{ ... }
end;
O único meio (fora a opção mencionada acima no caso do Turbo Pascal) é separar as partes da expressão lógica em um if dentro do outro.
if a < b then
if b < c then
begin
{ ... }
end;
No C a avaliação é incompleta, i.e., é feita o mínimo de operações necessárias para obter o resultado.
No exemplo equivalente abaixo, se a foi maior ou igual a b, a segunda comparação não será feita, pois já temos o resultado da expressão toda (No and basta um ser falso para o resultado final ser falso.). Mas se a for menor que b, então a segunda comparação será feita.
if( ( a < b ) && ( b < c ) )
{
/* ... */
}
Então o código acima é igual ao código abaixo. (Na realidade, é o código abaixo que é gerado na compilação, mas só com conhecimento de Assembler para entender isto.)
if( a < b )
if( b < c )
{
/* ... */
}
Como podemos usar a avaliação incompleta mais ainda a nosso favor?
Podemos colocar primeiro o que pode definir mais rapidamente o resultado final. Por exemplo, se tem mais chances de a ser maior ou igual a b - isto é, a primeira comparação ser falsa - do que a segunda comparação, então a ordem no exemplo acima está perfeita. Mas se tem mais chances de b ser maior ou igual a c - isto é, a segunda comparação ser falsa - do que a primeira comparação ser falsa, então é melhor mudar a ordem de avaliação das comparações, para um desempenho médio melhor. Serão menos vezes que a segunda comparação será feita.
Mas se a expressão for com or (||), e não and (&&), então devemos colocar em primeiro o que tem mais chances de ser verdadeiro.
if( ( a < b ) || ( b < c ) )
{
/* ... */
}
{
/* ... */
}
Se a primeira comparação tem mais chances de ser verdadeira, então tem mais chances da segunda comparação não ser avaliada.
Assim podemos usar, quando temos possibilidades mais conhecidas, a avaliação incompleta mais a nosso favor ainda.
E se uma comparação tem um grande custo? Um exemplo é uma comparação que tem um custo alto, como um strcmp(), por exemplo. Olhe os dois casos abaixo:
if( ( a < b ) && strcmp( c,d ) )
{
/* ... */
}
if( strcmp( c,d ) && ( a < b ) )
{
/* ... */
}
Qual dos dois casos acima é o melhor? No primeiro caso, a strcmp() somente será executada se a primeira comparação for verdadeira, e no segundo ela sempre será executada. Mesmo que a comparação entre a e b quase sempre tenha resultado verdadeiro, o consumo de tempo de processamento da strcmp() é tão mais alto do que uma simples comparação que, umas poucas vezes que ela não é executada dê um ganho de tempo significativo no processamento total.
Então, para aproveitar bem a avaliação incompleta, pode-se levar em conta a probabilidade dos resultados intermediários das expressões lógicas, e o custo de processamento para obter estes resultados intermediários.
Nenhum comentário:
Postar um comentário