Após uma introdução básica e uma parte essencialmente prática e de desenvolvimento da leitura lógica de um programa em Pascal, é altura de continuar com uma nova parte novamente teórica. Os Desafios doravante apresentados pretendem ser exercícios mais complexos que levam o “aprendiz” a pensar mais para poder chegar à conclusão. Nesta parte do Tutorial, dar-se-á ênfase à utilização de operadores para realização de cálculos (revisão prática), recorrendo sempre que possível a procedimentos e funções para que estes sejam treinados e seja entendida a sua importância na estruturação de um bom programa. Esta parte também começará a dar ênfase às boas práticas no acto da programação para a fácil leitura e interpretação de um programa Pascal. Começar-se-á igualmente com optimização de nível básico, e com comandos de coloração e outros direccionados a strings.
Para além das quatro operações básicas, existem outras suportadas pelo Pascal. Muitas foram já abordadas previamente, mas seguem-se como breve revisão prática.
SIN, COS e ARCTAN
program operacoes_01; uses crt; var a : real; begin write('Introduza angulo em RADIANOS: '); readln(a); write('Seno do angulo: ',SIN(a):0:3); // valor arredondado a 3 casas decimais write('Co-seno do ângulo: ',COS(a):0:3); write('Arco-tangente: ',ARCTAN(a):0:3); readln; end.
ROUND, TRUNC e ABS
Exemplo da sua utilização:
program operacoes_02; var r : real; begin write('Introduza numero real: '); readln(r); write('Arredondado às unidades: ',ROUND(r)); //equivale a “r:0:0”. Contudo, poderá gravar o valor arredondado numa variável, e “r:0:0” não o faz – tal não é permitido. write('Parte inteira: ',TRUNC(r)); write('Parte fraccionaria: ',ABS(r-TRUNC(r))); // considera-se a parte fraccionária sempre POSITIVA, daí a utilização da função ABS. write('Valor absoluto: ',ABS(r)); write('Absoluto da parte inteira: ',ABS(TRUNC(r))); readln; end.
DIV e MOD Estas são operações muito úteis, relacionadas com a divisão. Relembrando a Parte I do tutorial:
program operacoes_03; uses crt; var r, s : real; begin write('Introduza dois valores reais: '); readln(r, s); write('Divisao “normal”: ',r/s); // não é prevista a situação de s=0, para simplificação da leitura do programa. write('Div. Inteira: ',ROUND(r) DIV ROUND(s)); write('Resto: ',ROUND(r) MOD ROUND(s)); readln; end.
Optimização é o processo que permite reduzir o número de linhas de código: o programa realiza exactamente as mesmas operações com menos código, ou seja, o executável terá um tamanho menor, e poderá ser, porventura, mais rápido de ser processado. As primeiras optimizações que irão ser feitas serão na estrutura de decisão If… Then… Else…. A regra desta estrutura, como já foi visto, é a seguinte:
if (condição) then begin comandosA; end else begin comandosB; end;
No caso de comandosA ou comandosB serem uma e uma só instrução, optimiza-se a estrutura das seguintes formas:
// comandosA é uma só instrução: if (condição) then comandoA else begin comandosB; end; // comandosB é uma só instrução: if (condição) then begin comandosA; end else comandoB; // comandosA e comandosB são uma só instrução: if (condição) then comandoA else comandoB;
Por exemplo:
readln(numero); if (numero<0) then write('Numero negativo.') else begin if (numero>0) then write('Numero positivo') else write('Numero nulo'); end;
Agora, o mesmo se aplica a qualquer ciclo de repetição. No caso de o código a executar forem tão-somente uma instrução, ficará assim:
// ciclo WHILE while (condição) do comandoA; // Ciclo FOR for i:=1 to 10 do comandoB; for i:=1 downto 10 do comandoC;
Ou seja, em todos os casos, begin e end são as palavras reservadas omitidas. A única estrutura que não tem optimização possível é o ciclo Repeat… Until….
Imagine-se o seguinte caso. Pretende-se que o utilizador de um programa introduza um número real, em frente à mensagem que lhe colocarmos. Por exemplo, algo como:
write('Introduza um numero real: '); readln(numero);
Como o cursor fica à frente da mensagem e o número será introduzido em frente deste, o próprio código poderá dar a entender este facto da seguinte forma:
write('Introduza um numero real: '); readln(numero); // o cursor fica à frente da mensagem
Ou seja, o código em si dá a entender que o programa esperará o valor real (variável numero) à frente da mensagem. Isto é possível pois o ponto e vírgula (“ ; ”) é o símbolo que faz a separação dos códigos. Por esta razão é que, no código que antecede um else nunca é precedido de “;”, pois o programa só assim fica a saber que a condição if ainda não acabou e que encontrará imediatamente a seguir um senão (else).
A própria optimização estudada anteriormente facilita em muito a leitura de um programa, pois há menos “poluição visual” com uma série de begins e ends desnecessários. A leitura torna-se mais clara.
O uso de procedimentos e funções facilitará igualmente a leitura do código, para além de o optimizar. As seguintes duas linhas de código fazem exactamente o mesmo, contudo uma utiliza funções e outra não: (NB: As funções aqui apresentadas estão programadas na Parte II do tutorial.)
// sem recurso a funções: if (COS(a)<>0) then writeln('A tangente e: ',SIN(a)/COS(a):0:3) else writeln('Tangente impossivel'); // com recurso a funções: if tangente_possivel(a) then writeln('A tangente e: ',tan(a):0:3); else writeln('Tangente impossivel');
Com recurso a funções, consegue-se ler directamente o seguinte:
Se a tangente de a é possível então calcula-a, se não diz que é impossível.
Compare-se com o caso em que não há recurso a funções. A leitura é dificultada. Este é meramente um caso simplista. Casos mais complexos revelarão melhor a importância das funções e dos procedimentos na leitura fácil de um programa, mas tais casos não estão no âmbito deste Tutorial devido à sua complexidade (número de linhas de código envolvidas – o foco desta parte seria desviada para o entendimento do programa em si).
Pretende-se um programa que realize a Fórmula Resolvente, recorrendo a Procedimentos e Funções variados. Tópicos para o programa:
Cumprindo os variados tópicos, deve-se primeiramente definir como funcionará cada Função e cada Procedimento.
program formula_resolvente; var a, b, c : real; i : integer; function resolucao_possivel(d1:real) : boolean; // verifica se há solução real begin end; function d(a1:real; b1:real;c1:real) : real; // calcula o binómio discriminante begin end; function x(i:integer;a1:real;b1:real;c1:real) : real; // calcula o X nº “i”. begin end; begin writeln('Ax^2 + Bx + C = 0'); writeln('Introduza os tres coeficientes por ordem: '); readln(a, b, c); end.
Agora que o esqueleto do programa está montado, resta programá-lo de acordo com as funções de que se dispõe. Para treinar a leitura lógica de um programa que utilize funções, a explicação não será alongada. Claro que o exemplo seguinte tem funções utilizadas com um certo abuso, mas tal foi propositado.
program formula_resolvente; var a, b, c : real; i : integer; function resolucao_possivel(d1:real) : boolean; // verifica se há solução real begin if (d1>=0) then resolucao_possivel := true // se o Bin. Disc. For maior ou igual que zero, há soluções reais else resolucao_possivel := false; end; function d(a1:real; b1:real; c1:real) : real; // calcula o binómio discriminante begin d:=SQR(b1) – 4*a1*c1; end; function x(j:integer; a1:real; b1:real; c1:real) : real; // calcula o X nº “j”. begin case j of 1 : x := (-b1 + SQRT( d(a1, b1, c1) )) / (2*a1); 2 : x := (-b1 - SQRT( d(a1, b1, c1) )) / (2*a1); end; end; begin writeln('Ax^2 + Bx + C = 0'); writeln('Introduza os tres coeficientes por ordem: '); readln(a, b, c); if resolucao_possivel( d(a, b, c) ) then begin // se a resolução é possível (sabendo-se tal pelo Discriminante), então… for i:=1 to 2 do write('Solucao ',i,': ', x(i, a, b, c):0:3 ); end else begin write('Impossivel em R.'); end; readln; end.
Desafio 1 Crie um programa que leia o nome do utilizador e apresenta-o com os caracteres por ordem inversa. Por exemplo:
“Thoga 31” passará a ser “13 agohT”
Contudo, terá de criar uma função para:
Normas: livre
Existem, claro está, funções que permitem converter as variáveis de uns tipos para outros. É possível converter de Real para String, de String para Real, de Integer para Real e de Real para Integer. Existem outras variáveis, contudo, que não são abordadas de momento.
Sejam dadas as variáveis r, Real, e s, String. Sejam igualmente as variáveiserro e i, Integer.
str(s, r, erro); // Converter a string “s” para real, “r”. // Se tal não for possível, indicar a posição do erro, em “erro”.
A posição do erro consiste no índice da string no qual existe o erro. Exemplo:
574P5 – o erro está na posição 4: “P”.
str(s, i, erro); // Converter a string “s” para integer, “i”. // Se tal não for possível, indicar a posição do erro, em “erro”.
A posição do erro consiste no índice da string no qual existe o erro. Exemplo:
5.915 – o erro está na posição 2: “.”: um Integer não tem parte decimal.
val(r, s); // Converter o real “r” para string, “s”. val(i, s); // Converter o integer “i” para string, “s”.
A conversão de real/integer para string não implicará erro nenhum, caso o processo seja correctamente efectuado na CPU, o que não é previsto o contrário.
Considerando as mesmas variáveis:
r := i;
Não são necessárias normas para esta conversão, visto que um número inteiro (Integer) não passa de um caso especial do universo dos reais (Real). Logo são intimamente compatíveis nesta, e só nesta, conversão. Já o inverso não se verifica, pois um número real pode não pertencer ao universo dos inteiros. Para esta conversão, é necessário arredondar o Real, e o Pascal só reconhece esta operação com um de dois operadores: ROUND e TRUNC, cujas diferenças já foram previamente explicadas.
i := ROUND(r); i := TRUNC(r);
O sistema de cores que o pascal suporta é o seguinte:
Os códigos que permitem a aplicação de cores são os seguintes:
A cor predefinida do texto é a nº 7, e a de fundo é a nº 8.
textcolor(7); textbackground(8);
Para conhecer as cores do Pascal, pode-se construir o seguinte programa:
program cores; uses crt; var i : integer; begin writeln('Cores de TEXTO:'); for i:=1 to 16 do begin textcolor(i); write(' Cor ',i,' '); end; writeln; writeln('Cores do FUNDO:'); textcolor(15); // branco for i:=1 to 8 do begin textbackground(i); write(' Cor ',i,' '); end; writeln; end.
Desafio 2 Crie um programa que construa uma tabela em que, em cada coluna, fica uma cor de fundo, e em cada linha uma cor de texto, para que possam ser analisadas todas as combinações fundo/texto possíveis. Normas: livre
O sistema de caracteres do Pascal é o ASCII. Dependendo de cada país e/ou sistema, a tabela pode sofrer algumas modificações, as quais o Pascal é sensível pois ele recorre ao sistema ASCII do próprio computador e não a uma tabela ASCII própria. Para se conhecer a tabela ASCII de cada programa, é possível criar um programa que a debite. Contudo, é apresentada uma tabela padrão na Parte VI. Para saber o caracter de ordem i da tabela ASCII:
write( CHAR(i) );
Já para saber a ordem de um caracter:
write( ORD(caracter) );
Sendo caracter uma variável do tipo char.
No caso de string, para se saber a ordem de cada carácter dever-se-á realizar o seguinte ciclo:
for i:=1 to length(s) do write(ORD(s[i]),' ');
(i – variável Integer)
Só com o método CHAR é possível escrever acentuações em determinados IDEs/compiladores.
Desafio 3 Crie um programa que construa uma tabela ASCII, indicando a ordem seguida do carácter correspondente. Normas: livre
Desafio 4 Crie, num programa, tão-somente duas funções que façam uma conversão especial. Muitas vezes, o valor booleano True é associado ao número 1, e False ao número 0. Então, uma das funções converte um booleano no seu correspondente numérico. A outra função realizará o inverso. Normas: livre
Propostas de Exercícios 6. Crie uma calculadora que realize as quatro operações básicas, com previsão de erros, como o da divisão. Estes deverão ser escritos a vermelho vivo. Os textos deverão ser a branco e os resultados a amarelo vivo. Faça um programa em que, no fim, se possa optar se se deseja realizar novo cálculo ou se se deseja sair. Normas:
7. Um programa deverá desenhar a bandeira da França. Utilize ciclos for. Faça um procedimento para desenhar a bandeira, onde as variáveis de entrada serão a cor a utilizar, o número de colunas e o número de linhas a desenhar. Normas: