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
10
Expressõ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;
4
5.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 é 100
Observamos os seguintes regras importantes:
- a palavra chave
for
é seguida por uma variável, neste casoi
; - depois temos a palavra
in
seguida por uma lista (Seção 3.1); - depois da lista temos a palavra
do
; - o laço está fechado pela palavra
od
(do
reverso).
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 é 100
As 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
do
eod
enquanto (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 é 81
Observamos que
- O laço está iniciado pela palavra
repeat
; - na última linha, temos a palavra
until
seguida por uma condição lógica; - o sistema termina a execução do laço assim que a condição depois de
repeat
vira 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 repeat
a 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 é 121
5.5 Tarefa
- Calcule os cubos dos números entre \(10\) e \(20\) usando laço
for
,while
erepeat
. - 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 );
16
Observe 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 distintos #
Nos 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*:44
As ú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;
-5
Funçõ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 );
3
GAP
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... ) ... end
Esta 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);
2
5.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
10
5.9 Tarefa
- Resolve o item 2. da tarefa na Seção 5.5 usando a expressão
continue
. - Usando
while true do
ebreak
ache o menor primo que seja maior que \(10000000\) (useIsPrimeInt
).