5 A linguagem de programação
Nesta página vamos revisar os aspetos principais da linguagem de programação do sistema GAP.
5.1 Expressões if-then-else
A expressão if-then (manual) está usada quando queremos executar instruções de acordo com alguma condição que pode ser verdadeira ou falsa (Seção 2.2). Considere o seguinte exemplo:
gap> a := 3; # seja a inicialmente 3
3
gap> if a mod 2 = 0 then # se a for par, dividimos a por 2
> a := a/2;
> fi;
gap> a; # valor de a continua 3
3
gap> if a mod 2 = 1 then # se a for ímpar, multiplicamos a por 3 e somamos 1
> a := 3*a+1;
> fi;
gap> a; # o valor de a mudou
10Expressões mais complicadas podem ser montadas usando as expressões else e elif.
gap> a := 3;
3
gap> if a mod 2 = 0 then
> a := a/2;
> else
> a := 3*a+1;
> fi;
gap> a;
10
gap> a := 8;
8
gap> if a mod 2 = 0 then
> a := a/2;
> elif a mod 2 = 1 then
> a := 3*a+1;
> else
> a := -2
> fi;
gap> a;
45.2 Laço for
Usamos for quando queremos executar a mesma peça de código várias vezes (manual). Por exemplo, queremos calcular o quadrado dos números entre 1 e 10.
gap> for i in [1..10] do
> Print( "O quadrado de ", i, " é ", i^2, "\n" );
> od;
O quadrado de 1 é 1
O quadrado de 2 é 4
O quadrado de 3 é 9
O quadrado de 4 é 16
O quadrado de 5 é 25
O quadrado de 6 é 36
O quadrado de 7 é 49
O quadrado de 8 é 64
O quadrado de 9 é 81
O quadrado de 10 é 100Observamos os seguintes regras importantes:
- a palavra chave
foré seguida por uma variável, neste casoi; - depois temos a palavra
inseguida por uma lista (Seção 3.1); - depois da lista temos a palavra
do; - o laço está fechado pela palavra
od(doreverso).
O ciclo executa o código entre as palavras do e od para todo valor i na lista que aparece depois da palavra in.
5.3 Laço while
Uma outra maneira de criar um laço é usar a construção com while (manual). Considere o seguinte exemplo.
gap> while i <= 10 do
> Print( "O quadrado de ", i, " é ", i^2, "\n" );
> i := i + 1;
> od;
O quadrado de 0 é 0
O quadrado de 1 é 1
O quadrado de 2 é 4
O quadrado de 3 é 9
O quadrado de 4 é 16
O quadrado de 5 é 25
O quadrado de 6 é 36
O quadrado de 7 é 49
O quadrado de 8 é 64
O quadrado de 9 é 81
O quadrado de 10 é 100As regras de construir este tipo de laço são as seguintes:
- a palavra
while(enquanto) está seguida por uma condição lógica (booleana) e depois pela palavrado; - o laço está fechado pela palavra
od; - a peça de código está executada entre as palavras
doeodenquanto (while) a condição está verdadeira (Seção 2.2).
Note que no laço while, o valor da variável i precisa ser incrementado manualmente.
5.4 Laço repeat
O terceiro tipo de laço pode ser construído com a palavra repeat (manual). Considere o seguinte exemplo:
gap> i := 0;
0
gap> repeat
> Print( "O quadrado de ", i, " é ", i^2, "\n" );
> i := i + 1;
> until i = 10;
O quadrado de 0 é 0
O quadrado de 1 é 1
O quadrado de 2 é 4
O quadrado de 3 é 9
O quadrado de 4 é 16
O quadrado de 5 é 25
O quadrado de 6 é 36
O quadrado de 7 é 49
O quadrado de 8 é 64
O quadrado de 9 é 81Observamos que
- O laço está iniciado pela palavra
repeat; - na última linha, temos a palavra
untilseguida por uma condição lógica; - o sistema termina a execução do laço assim que a condição depois de
repeatvira verdadeira (Seção 2.2).
A diferença entre os laços construídos por while e repeat é que no caso de while, a decisão está feita antes da execução do código, enquanto no caso de repeata mesma decisão está feita depois da execução. Em particular, o laço repeat sempre será executado pelo menos uma vez. Considere o seguinte código e explique o comportamento.
gap> i := 11;
11
gap> while i <= 10 do
> Print( "O quadrado de ", i, " é ", i^2, "\n" );
> i := i + 1;
> od;
gap> i := 11;
11
gap> repeat
> Print( "O quadrado de ", i, " é ", i^2, "\n" );
> i := 11;
> until i >= 10;
O quadrado de 11 é 1215.5 Tarefa
- Calcule os cubos dos números entre \(10\) e \(20\) usando laço
for,whileerepeat. - Modifique os laços no item anterior, usando
if, em tal forma que apenas os cubos dos números pares serão calculados.
5.6 Funções
Funções em GAP podem ser usadas para realizar computações que queremos fazer várias vezes com diferentes objetos. Por exemplo a função que, dado x, computa 3*x+1 pode ser definida de duas maneiras diferentes.
gap> f1 := function( x )
> return 3*x+1;
> end;
function( x ) ... end
gap> f1( 5 );
16Observe que o valor da função é devolvido pela expressão return.
gap> f2 := x -> 3*x + 1;
function( x ) ... end
gap> f2( -2 );
-5
gap> f1 = f2;
false
# As funções f1 e f2 fazem a mesma coisa, mas são objetos distintosNos exemplos anteriores, a função não precisa de variáveis adicionais para executar sua tarefa. Isso pode acontecer com funções simples, mas uma função mais complicada pode precisar introduzir as suas próprias variáveis, chamadas de variáveis locais. Considere a seguinte implementação do exemplo em cima.
gap> f3 := function( x )
> local y;
> y := 3*x;
> return y+1;
> end;
function( x ) ... end
gap> f3(4);
13
gap> y;
Error, Variable: 'y' must have a value
not in any function at *stdin*:44As últimas linhas do exemplo anterior mostram que o variável y não está visível fora da função. Isso permite que variáveis com o mesmo nome sejam usadas em várias funções sem que sejam confundidas. O mesmo também impede que a varíavel local y definida dentro da função f3 seja confundida com uma possível variável global também chamada de y. O seguinte código mostra que o nome y tem significado diferente dentro e fora da função.
gap> f3 := function( x )
> local y;
> y := 3*x;
> Print( "O valor de y é ", y, "\n" );
> return y+1;
> end;
function( x ) ... end
gap> y := -5;
-5
gap> f3(10);
O valor de y é 30
31
gap> y;
-5Funções podem receber mais que um argumento. Considere o seguinte exemplo.
gap> my_sum := function( x, y )
> return x+y;
> end;
function( x, y ) ... end
gap> my_sum( 4, -1 );
3GAP permite também um número varíavel de argumentos como no seguinte exemplo.
gap> f4 := function( a, args... )
> local b;
> if Length( args ) > 0 then
> b := args[1];
> else
> b := true;
> fi;
> if b then
> return 3*a-1;
> else
> return a/2;
> fi;
> end;
function( a, args... ) ... endEsta função devolve \(3a-1\) se tem apenas um argumento. No entanto, o usuário pode fornecer um segundo argumento que pode ser true ou false. No caso de true, a função devolve \(3a-1\), mas no caso de false, a função devolve \(a/2\).
gap> f4(4);
11
gap> f4(3);
8
gap> f4(3, true);
8
gap> f4(3, false);
3/2
gap> f4(4, false);
25.7 Tarefa
- Escreva uma função
collatz( n )que devolve \(3n-1\) quando \(n\) for ímpar e \(n/2\) quando \(n\) for par. - Escreva uma função
sum_divisors( n )que devolve a soma dos divisores entre \(1\) e \(n-1\) de um número natural \(n\).
No item 1., precisa testar, usando if, (Seção 5.1) se o input é par ou ímpar e para isso pode usar a operação mod (Seção 2.1). Se precisar de ajuda com funções, consulte a Seção 5.6.
No item 2., pode usar as funções DivisorsInt (manual) e Sum (manual). Também pode precisar de if para decidir se n=0, pois DivisorsInt( 0 ) não funciona (Seção 5.1).
5.8 Break e continue
As expressões break (manual) e continue (manual) podem ser usadas em laços.
Quando a expressão break está executada, o sistema sai do laço. No caso de continue, o sistema sai da iteração atual e passa para a próxima iteração.
gap> for i in [1..10] do
> if i = 5 then break; fi;
> Print( i, "\n" );
> od;
1
2
3
4
gap> for i in [1..10] do
> if i = 5 then continue; fi;
> Print( i, "\n" );
> od;
1
2
3
4
6
7
8
9
105.9 Tarefa
- Resolve o item 2. da tarefa na Seção 5.5 usando a expressão
continue. - Usando
while true doebreakache o menor primo que seja maior que \(10000000\) (useIsPrimeInt).