Mudanças entre as edições de "Lógica de Programação - Subprogramas"
(30 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 23: | Linha 23: | ||
===Solução 1 - inserindo código de repetição para resolver a potenciação === | ===Solução 1 - inserindo código de repetição para resolver a potenciação === | ||
+ | |||
+ | OBS: Vamos considerar uma solução para potências maiores ou igual a 0. | ||
<syntaxhighlight lang="code"> | <syntaxhighlight lang="code"> | ||
Linha 47: | Linha 49: | ||
FIM_ENQUANTO | FIM_ENQUANTO | ||
− | z ← prod1 + prod2 | + | z ← prod1 + prod2; |
− | mostrar z | + | mostrar z; |
FIM | FIM | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | ===Solução 2 - Usando subprograma para resolver a potenciação === | ||
Vamos identificar agora o padrão que se repete para solucionar o "subproblema" potenciação: | Vamos identificar agora o padrão que se repete para solucionar o "subproblema" potenciação: | ||
− | |||
[[imagem:DestaqueCodigos.png|border|450px]] | [[imagem:DestaqueCodigos.png|border|450px]] | ||
Linha 64: | Linha 67: | ||
<syntaxhighlight lang="code"> | <syntaxhighlight lang="code"> | ||
− | ALGORITMO pow(numero: real, potencia: | + | ALGORITMO pow(numero: real, potencia: inteiro) |
VARIAVEIS | VARIAVEIS | ||
i: inteiro; | i: inteiro; | ||
Linha 72: | Linha 75: | ||
i ← 0; | i ← 0; | ||
ENQUANTO i < potencia FAÇA | ENQUANTO i < potencia FAÇA | ||
− | + | prod ← prod * numero; | |
i ← i+1; | i ← i+1; | ||
FIM_ENQUANTO | FIM_ENQUANTO | ||
− | RETORNA | + | RETORNA prod |
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 83: | Linha 86: | ||
ALGORITMO funcao_xyz() | ALGORITMO funcao_xyz() | ||
VARIAVEIS | VARIAVEIS | ||
− | x,y,z | + | x,y,z: real; |
− | |||
INICIO | INICIO | ||
LER x; | LER x; | ||
LER y; | LER y; | ||
− | z | + | z ← POW(x,7) + POW(y,3); |
mostrar z; | mostrar z; | ||
FIM | FIM | ||
Linha 95: | Linha 97: | ||
<blockquote style="background: lime; border: 1px solid black; padding: 1em;"> | <blockquote style="background: lime; border: 1px solid black; padding: 1em;"> | ||
− | Observe a redução de complexidade do código original em relação a versão usando o subprograma POW(). Pode-se interpretar a execução da linha de código <code>z = POW(x,7) + POW(y,3); </code> como: | + | Observe a redução de complexidade do código original em relação a versão usando o subprograma POW(). Pode-se interpretar a execução da linha de código <code>z = POW(x,7) + POW(y,3);</code> como: |
<ol> | <ol> | ||
<li> | <li> | ||
Chame o subprograma POW e repasse para ele os valores de x e o valor 7. O fluxo de execução é desviado para o subprograma. O "parâmetro" numero recebe o valor de x e o parametro potencia recebe o valor 7. | Chame o subprograma POW e repasse para ele os valores de x e o valor 7. O fluxo de execução é desviado para o subprograma. O "parâmetro" numero recebe o valor de x e o parametro potencia recebe o valor 7. | ||
</li> | </li> | ||
− | + | <li> | |
− | + | O subprograma se executa e retorna o valor computado. Este valor fica armazenado em uma área temporária. | |
− | + | </li> | |
− | + | <li> | |
+ | O fluxo de execução continua no programa principal e novamente é invocado (chamado) o suprograma POW(), agora com novos parâmetros. | ||
+ | </li> | ||
+ | <li> | ||
+ | O subprograma se executa e retorna o valor. | ||
+ | </li> | ||
+ | <li>Estes valor será agora somado com o valor temporário (resultante da primeira chamada de POW()). O resultado da soma e colocado (atribuído) a z. | ||
+ | </li> | ||
</ol> | </ol> | ||
</blockquote> | </blockquote> | ||
− | ==CASO DE ESTUDO 2: Controle de Acesso== | + | |
+ | [[imagem:FluxoChamadaSubprogramaV2.png|border|550px]] | ||
+ | |||
+ | ===EXERCÍCIO=== | ||
+ | |||
+ | Modificar o subprograma para que as potências possam ser negativas (ver [https://pt.wikipedia.org/wiki/Exponencia%C3%A7%C3%A3o#:~:text=Expoentes%20inteiros%20negativos,-Para%20que&text=seja%20v%C3%A1lido%20para%20n%20%2B%20m,pot%C3%AAncia%20%2D1%20produza%20seu%20inverso.&text=Elevando%200%20a%20uma%20pot%C3%AAncia,por%200%2C%20sendo%20assim%20indefinido. link]). | ||
+ | |||
+ | ==CASO DE ESTUDO 2: Cálculo de fatorial== | ||
+ | |||
+ | Seja elaborar um fluxograma correspondente a uma subprograma que deve calcular o fatorial de um número inteiro passado como parâmetro. O subprograma deve retornar o valor calculado. Mostrar um exemplo de algoritmo que usa o subprograma de cálculo de fatorial, chamando-o duas vezes. | ||
+ | |||
+ | A função fatorial é definida por: | ||
+ | |||
+ | :<math>n!=\prod_{k=1}^n k\qquad\forall n\in\mathbb{N}</math> | ||
+ | |||
+ | [[imagem:FluxogramaFatorial.jpg|border|650px]] | ||
+ | |||
+ | Neste fluxograma, o subprograma denominado ''CalcFatorial'' recebe um valor no parâmetro N (implicitamente inteiro) e retorna o valor calculado do fatorial. O parâmetro é passado por cópia neste caso. | ||
+ | |||
+ | O fluxograma principal invoca duas vezes o subrograma. O retorno é armazenado nas variáveis NUM1 e NUm3. | ||
+ | |||
+ | Quando um subprograma retorna um valor, ele é chamado de função. Para manter coerência com o C chamaremos | ||
+ | qualquer subrprograma de função (independente de retornar valor). | ||
+ | |||
+ | ==CASO DE ESTUDO 3: Controle de Acesso - Um exemplo QUASE sem matemática== | ||
Vamos retomar inicialmente o problema de controle de acesso: | Vamos retomar inicialmente o problema de controle de acesso: | ||
Linha 158: | Linha 191: | ||
=PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMAS= | =PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMAS= | ||
− | Para tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores. | + | Para tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores com mais detalhes. |
Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma. | Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma. | ||
Linha 171: | Linha 204: | ||
Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro. | Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro. | ||
− | + | ==Um exemplo de passagem de parâmetro por referência== | |
− | A | + | A passagem de parâmetro por referência permite "repassar valores" nos dois sentidos. Funciona como se fosse entrada/saída de dados. Na prática, não existe cópia de valores, o que existe é uma espécie de compartilhamento de variáveis entre o subprograma e o programa(algoritmo) que chama o subprograma. Isto pode ser interessante em várias situações. Por exemplo, existem linguagens de programação que não permite retornar mais do que um valor. Neste caso, valores podem ser repassados (retornados) pelos parâmetros. |
− | :<math> | + | Vamos "testar" esta ideia implementando um subprograma calcula o ponto médio <math>P(x_M,y_M)</math> de um segmento de reta definido por dois pontos: |
+ | <math>A(x_A,y_A)</math> e <math>B(x_B,y_B)</math>. Sabe-se que um ponto possui na realidade dois valores reais a serem retornados, o que complica o retorno pelo comando RETORNAR. Uma possível implementação do subprograma seria: | ||
− | + | <syntaxhighlight lang="code"> | |
+ | ALGORITMO ponto_medio(pxa: real, pya:real, pxb: real, pyb:real, VAR pxm: real, pym:real) | ||
+ | INICIO | ||
+ | pxm ← (pxa + pxb)/2; | ||
+ | pym ← (pya + pyb)/2; | ||
+ | RETORNA | ||
+ | </syntaxhighlight> | ||
− | + | Observe que os parâmetros xm e ym foram declarados com VAR, indicando que serão passados como referência. | |
− | O | + | O uso deste subprograma poderia ser: |
− | + | <syntaxhighlight lang="code"> | |
− | + | ALGORITMO teste_media | |
− | + | VARIAVEIS: | |
− | + | xa,ya,xb,yb,xm,ym: reais | |
+ | INICIO | ||
+ | LER xa; | ||
+ | LER ya; | ||
+ | LER xb; | ||
+ | LER yb; | ||
+ | ponto_medio(xa,ya,xb,yb,xm,ym); | ||
+ | MOSTRAR xm; | ||
+ | MOSTRAR ym; | ||
+ | RETORNA | ||
+ | </syntaxhighlight> | ||
− | + | Deve ser observado que houve o algoritmo que chamou o subprograma, recebeu nas variáveis xm e ym os valores calculados pelo subprograma. Isso não aconteceria se não fosse passagem por referência. |
Edição atual tal como às 18h23min de 18 de agosto de 2023
Objetivos da Aula
Após esta aula o aluno deverá ser capaz de:
- Identificar padrões/blocos de código que se repetem na solução de determinados problemas;
- Encapsular blocos de código na forma de subprogramas/subprocessos, representado-os com fluxogramas e pseudocódigo;
- Identificar os dados de entrada de subprogramas, representado-os na forma de parâmetros do subprograma;
- Identificar valores de retorno de subprogramas;
- Aplicar subprogramas/subprocessos na solução algorítmica de problemas diversos.
Quebrando um problema em subproblemas: SUBPROGRAMAS
CASO DE ESTUDO 1: Elevando um número a uma potência inteira
Em várias algoritmos surge a necessidade de "elevar" um número a uma potência inteira. Muitos sistemas computacionais não conseguem implementar esta operação através uma operação simples da CPU. O que deve ser feito é multiplicar repetidas vezes o número de forma a se obter a operação de potenciação. Neste caso, um dado problemas simples, cuja solução requer o uso de potenciação em várias partes do algoritmo, deve replicar o código, abrindo espaço para possíveis erros, além de aumentar desnecessariamente o tamanho do algoritmo.
EXEMPLO: Implementar um algoritmo na forma de pseudocódigo de forma a resolver a seguinte equação:
DADOS DE ENTRADA: valor de x e de y
DADOS DE SAÍDA: valor computado de z
Solução 1 - inserindo código de repetição para resolver a potenciação
OBS: Vamos considerar uma solução para potências maiores ou igual a 0.
ALGORITMO funcao_xyz()
VARIAVEIS
x,y,z,prod1, prod2: real;
i: inteiro;
INICIO
LER x;
LER y;
prod1 ← 1;
i ← 0;
ENQUANTO i < 7 FAÇA
prod1 ← prod1 * x;
i ← i+1;
FIM_ENQUANTO
prod2 ← 1;
i ← 0;
ENQUANTO i < 3 FAÇA
prod2 ← prod2 * y;
i ← i+1;
FIM_ENQUANTO
z ← prod1 + prod2;
mostrar z;
FIM
Solução 2 - Usando subprograma para resolver a potenciação
Vamos identificar agora o padrão que se repete para solucionar o "subproblema" potenciação:
Podemos observar que nos dois blocos aparecem as variáveis x e y que possuem os valores que desejamos elevar a uma potência. A potência propriamente dita aparece na forma de uma contante (7 e 3). Além disso, as variáveis auxiliares (prod1 e prod2) são usadas para armazenar o produto acumulado.
Tendo identificado o padrão que se repete vamos encapsular o mesmo em um SUBPROGRAMA:
ALGORITMO pow(numero: real, potencia: inteiro)
VARIAVEIS
i: inteiro;
prod: real;
INICIO
prod ← 1;
i ← 0;
ENQUANTO i < potencia FAÇA
prod ← prod * numero;
i ← i+1;
FIM_ENQUANTO
RETORNA prod
Finalmente, vamos USAR (CHAMAR) este subprograma a partir do algoritmo principal:
ALGORITMO funcao_xyz()
VARIAVEIS
x,y,z: real;
INICIO
LER x;
LER y;
z ← POW(x,7) + POW(y,3);
mostrar z;
FIM
Observe a redução de complexidade do código original em relação a versão usando o subprograma POW(). Pode-se interpretar a execução da linha de código
z = POW(x,7) + POW(y,3);
como:
- Chame o subprograma POW e repasse para ele os valores de x e o valor 7. O fluxo de execução é desviado para o subprograma. O "parâmetro" numero recebe o valor de x e o parametro potencia recebe o valor 7.
- O subprograma se executa e retorna o valor computado. Este valor fica armazenado em uma área temporária.
- O fluxo de execução continua no programa principal e novamente é invocado (chamado) o suprograma POW(), agora com novos parâmetros.
- O subprograma se executa e retorna o valor.
- Estes valor será agora somado com o valor temporário (resultante da primeira chamada de POW()). O resultado da soma e colocado (atribuído) a z.
EXERCÍCIO
Modificar o subprograma para que as potências possam ser negativas (ver link).
CASO DE ESTUDO 2: Cálculo de fatorial
Seja elaborar um fluxograma correspondente a uma subprograma que deve calcular o fatorial de um número inteiro passado como parâmetro. O subprograma deve retornar o valor calculado. Mostrar um exemplo de algoritmo que usa o subprograma de cálculo de fatorial, chamando-o duas vezes.
A função fatorial é definida por:
Neste fluxograma, o subprograma denominado CalcFatorial recebe um valor no parâmetro N (implicitamente inteiro) e retorna o valor calculado do fatorial. O parâmetro é passado por cópia neste caso.
O fluxograma principal invoca duas vezes o subrograma. O retorno é armazenado nas variáveis NUM1 e NUm3.
Quando um subprograma retorna um valor, ele é chamado de função. Para manter coerência com o C chamaremos qualquer subrprograma de função (independente de retornar valor).
CASO DE ESTUDO 3: Controle de Acesso - Um exemplo QUASE sem matemática
Vamos retomar inicialmente o problema de controle de acesso:
PROBLEMA: Aprimorar o exemplo do controle de acesso para que, no caso de 3 tentativas de acesso seguidas, com senha errada, o sistema seja bloqueado. O administrador desbloqueia redefinindo a senha e zerando o contador de acesso.
- DADOS DE ENTRADA: senha inserida pelo usuário na variável SENHA /* variável que armazena a senha entrada pelo usuário ou administrador */
- DADOS DE SAÍDA: mensagem de abertura da porta / usuário bloqueado*/
- VARIÁVEIS INTERMEDIÁRIAS: CONT_ACESSO /* valor inicial zero - incrementada a cada senha inválida */
Note que a variável CONT_ACESSO é iniciada com zero e incrementada a cada erro no fornecimento da senha. A atribuição CONT_ACESSO = CONT_+ACESSO + 1 deve ser interpretada da forma: acesse o valor de CONT_ACESSO e some 1 a este valor. Coloque o resultado novamente em CONT_ACESSO (o conteúdo anterior é sobrescrito!)
Esta solução não é perfeita e poderia ser aprimorada. Se o administrador erra, ele pode vir a bloquear o usuário.
Neste procedimento pode ser observado que:
- começa a aparecer uma certa complexidade no fluxograma;
- além disto, não ficou uma abordagem muito interessante, pois se for o administrador que erra a senha, ele pode bloquear o usuário. Mudando a ordem de teste pode-se contornar este problema.
- não existe forma de desbloquear a senha (zerar o contador), a não ser mudando a senha.
Em síntese, existem subproblemas adicionais a serem resolvidos que adicionam complexidade ao sistema. Como podemos resolvê-los sem deixar um fluxograma complexo?
Usaremos a caixa de processos pré-definidos que usaremos para invocar funções que resolvem determinado subproblema.
Inicialmente, vamos construir três subprogramas:
- Iniciar_Sistema(): inicia variáveis do sistema, colocando o sistema em um estado inicial conhecido;
- Tratar_Admin(): é o código que trata a funcionalidade associada ao administrador;
- Tratar_User(): é a funcionalidade que trata o usuário (procedimento de abrir porta, bloquear etc).
OBS: Note que foi usada uma variável auxiliar AUX que permite ajustar o valor de número de acessos a ser mostrado no display. Note também que na caixa DISPLAY foi usado uma string a ser impressa e a variável AUX cujo conteúdo deve ser impresso. Ambos separados por vírgula.
- ANINHAMENTO DE DECISÔES
A função Tratar_User() se utiliza de aninhamento de decisões. Em um primeiro momento é testado se a senha confere com a senha do usuário. SE ela conferir ENTÂO é testado se o contador de bloqueios está dentro do aceitável.
PARÂMETROS E RETORNO DE VALORES EM SUBPROGRAMAS
Para tornar ainda mais interessante o uso de subprogramas, vamos ver o conceito de passagem de parâmetros e retorno de valores com mais detalhes.
Quando chamamos (invocamos) um subprograma podemos passar valores (dados de entrada) para este subprograma. Estes valores são passados através de variáveis especiais que chamamos de parâmetros.
Parâmetros podem ser passados por valor e por referência. Por valor é quando os dados a serem passados na invocação do subprograma são copiados para uma variável do subprograma.
Os parâmetros são passados por referência quando o que é passado para o subprograma é simplesmente o endereço da variável repassada na invocação do subprograma.
Não existe uma forma explícita de definir os parâmetros em um fluxograma. Deve-se realizar um comentário antes ou ao lado do mesmo especificando o tipo e como será tratado o parâmetro.
Um exemplo de passagem de parâmetro por referência
A passagem de parâmetro por referência permite "repassar valores" nos dois sentidos. Funciona como se fosse entrada/saída de dados. Na prática, não existe cópia de valores, o que existe é uma espécie de compartilhamento de variáveis entre o subprograma e o programa(algoritmo) que chama o subprograma. Isto pode ser interessante em várias situações. Por exemplo, existem linguagens de programação que não permite retornar mais do que um valor. Neste caso, valores podem ser repassados (retornados) pelos parâmetros.
Vamos "testar" esta ideia implementando um subprograma calcula o ponto médio de um segmento de reta definido por dois pontos: e . Sabe-se que um ponto possui na realidade dois valores reais a serem retornados, o que complica o retorno pelo comando RETORNAR. Uma possível implementação do subprograma seria:
ALGORITMO ponto_medio(pxa: real, pya:real, pxb: real, pyb:real, VAR pxm: real, pym:real)
INICIO
pxm ← (pxa + pxb)/2;
pym ← (pya + pyb)/2;
RETORNA
Observe que os parâmetros xm e ym foram declarados com VAR, indicando que serão passados como referência.
O uso deste subprograma poderia ser:
ALGORITMO teste_media
VARIAVEIS:
xa,ya,xb,yb,xm,ym: reais
INICIO
LER xa;
LER ya;
LER xb;
LER yb;
ponto_medio(xa,ya,xb,yb,xm,ym);
MOSTRAR xm;
MOSTRAR ym;
RETORNA
Deve ser observado que houve o algoritmo que chamou o subprograma, recebeu nas variáveis xm e ym os valores calculados pelo subprograma. Isso não aconteceria se não fosse passagem por referência.