Showing posts with label processamento. Show all posts
Showing posts with label processamento. Show all posts

Saturday, March 24, 2012

Cálculo do tempo de processamento de algoritmos


Como já sabido, toda operação de computador requer um certo tempo e “esforço” do processador para acontecer. Quando programamos um computador, também é sabido que podemos produzir diversos códigos diferentes para obter o mesmo resultado, de forma similar a chegar a um mesmo resultado em Matemática a partir de distintas formas de fazer a mesma coisa. Contudo, meios diferentes requerem diferentes esforços, sejam nossos ou dos processadores, dando-nos mais ou menos trabalho, exigindo-nos mais ou menos tempo.

Com computadores, estamos falando de algoritmos, estas seqüências lógicas de processamento, se corretamente escolhidas, podem facilitar todo o processo na questão tempo e esforço.

O possível estimar o tempo de execução de algoritmos com a finalidade de saber quais são os melhores quando comparados uns com os outros, e é disso que venho falar.

A performance de um computador é determinada por fatores como:

·          Hardware:
o    Processador usado
o    Memória disponível
o    Disco disponível
·          Software
o    Linguagem e plataforma utilizada
o    Compilador usado
o    Sistema Operacional utilizado

Alguns exemplos de tempos exigidos para tarefas diversas:
  • ·    tfetch => tempo necessário para obter um dado (variável do programa) da memória
  • ·    tstore => tempo necessário para salvar um dado na memória (armazená-lo em uma variável)
  • ·    t+ => tempo necessário para executar uma operação de soma. Representações similares existem para as outras 3 operações elementares
  • ·    t< => tempo necessário para realizar a comparação lógica “menor que”. Existe a equivalente para “maior que”
  • ·    treturn => tempo necessário para finalizar a execução de um método/função, a partir do momento em que a instrução de código “return” é acionada
  • ·    t[.] => tempo necessário para calcular endereços quando trabalhando-se com “arrays”

Exemplos (Te = tempo de execução):

Exemplo 1: 

y = x;
Te = tfetch + tstore

Exemplo 2:

y = y + 1;
Te = 2(tfetch) + t+ + tstore

Primeiro exercício abordado em sala:

O seguinte código foi abordado em sala para calcularmos o tempo de processamento (funciona em C, C++, C# e Java):

// 1) int result = 0;
// 2) for (int i = 1; i <= n; ++i)
// 3) {
// 4)            result += i;
// 5) }
// 6) return result;

Obviamente, o código não está completo, sempre há código necessário tanto antes como depois dessas instruções, em qualquer linguagem, para poder compilar e executar tais instruções.

Vale a pena lembrar também que

result += i;

é uma forma abreviada de escrever

result = result + 1;

Vamos então ao cálculo do tempo de processamento. Resolverei primeiro da forma que o professor fez em sala, e depois, mostrarei uma forma alternativa que pensei aqui que, quando testando, dão o mesmo resultado, e achei bem mais simples do que o método do professor.

Professor:

// 1) tfetch + tstore
// 2) tfetch + tstore
// 2) [2(tfetch) + t<] * (n + 1)
// 2) [2(tfetch) + t+ + tstore] * n
// 4) [2(tfetch) + t+ + tstore] * n
// 6) tfetch + treturn
________________________________________________ +
[6(tfetch) + 2(tstore) + t< + 2(t+)] * n + 5(tfetch) + 2(tstore) + t< + treturn

Minha forma alternativa:

Para facilitar, vou criar variáveis de mais fácil manipulação para nós que estamos acostumados com Álgebra e Polinômios desde o ginásio (primeiro grau):

tfetch = x
tstore = y
t< = w
t+ = z
treturn = s
(n + 1) = a
n = b

Agora, basta trabalhar com x, y , w, z, s, a e b. Veja como fica:

// 1) x + y
// 2) x + y
// 2) (2x + w) * a
// 2) (2x + z + y) * b
// 4) (2x + z + y) * b
// 6) x + s
____________________ + (agrupando termos iguais)
2 (x + y)
a * (2x + w)
2b * (2x + z + y)
x + s
____________________ + (aplicando a distributiva, somando e agrupando os monômios similares)
(2x + 2y) + (2xa + aw) + (4bx + 2bz + 2by) + (x + s) =
3x + 2y + 2xa + aw + 4bx + 2bz + 2by + s (está resolvido)

Agora que a Álgebra foi realizada, trazendo novamente a nomenclatura técnica, fica assim:
3(tfetch) + 2(tstore) + 2[(n + 1)(tfetch)] + [(n + 1)(t<)] + 4 [n(tfetch)] + 2[n(t+)] + 2[n(tstore)] + treturn

Para testar os resultados, tanto o do professor quanto o meu, que visualmente não há indicações de serem equivalentes, basta escolher um valor para a variável “n” e verificar o que obtemos. Ambos dão o mesmo resultado, portanto são equivalentes, e vou mostrar isso escolhendo arbitrariamente o valor 4 para a variável “n”. Temos portando 2 resultados:

Professor:

[6(tfetch) + 2(tstore) + t< + 2(t+)] * n + 5(tfetch) + 2(tstore) + t< + treturn

Meu:

3(tfetch) + 2(tstore) + 2[(n + 1)(tfetch)] + [(n + 1)(t<)] + 4 [n(tfetch)] + 2[n(t+)] + 2[n(tstore)] + treturn

Testando a equivalência, para n = 4:

Em ambos os casos, obtemos
29(tfetch) + 10(tstore) + 5(t<) + 8(t+) + treturn

Conclusão:

Confesso que não entendi a última etapa do método do professor, e como preciso de um método para calcular isso (as provas chegarão um dia), acabei pensando na forma acima, que eu acredito simplificar o entendimento durante todo o processo, facilitando para não se perder durante as contas.

Eu acredito que ele fez da forma que fez porque ele quis agrupar o resultado de forma a ser visível através da fórmula

T(n) = t1 + t2n

sendo:
t1 = 5(tfetch) + 2(tstore) + t< + treturn
t2 = [6(tfetch) + 2(tstore) + t< + 2(t+)] * n

Esta é uma fórmula geral para tal tipo de cálculo dentro de um looping “for”. Caso fosse um looping “for” dentro de outro, também conhecido como “nested loop”, de acordo com o professor, a fórmula seria

T(n) = t1 + t2n2

Bom, é isso o que tenho a dizer no momento. Espero que o conteúdo acima sirva para os companheiros de sala e para todos que dependam deste entendimento.

Abraços!