Aula 8: Selecção/Ramificação II / Álgebra Booleana |
George Boole (1815-1864)
English mathematician. His work "The mathematical analysis of logic"
(1847) established the basis of modern mathematical logic, and his boolean
algebra can be used in designing computers.
|
Na aula anterior (aula 7) vimos como se pode controlar
o fluxo de um programa utilizando as instruções de selecção
if
... e if ... else .... Usamos condições como
(x<1.0). Imaginemos agora que queremos calcular a raíz quadrada
de (x2-4). Claramente,
não existe resposta para x entre -2
e +2. É importante verificar se x se encontra neste intervalo
ou não. Podemos resolver a situação assim:
if (x<2)
if (x>-2)
printf("Error");
Mas seria muito melhor se pudéssemos fazê-lo com uma única
condição. E tal é possível, vamos ver como:
if ((x<2) && (x>-2))
printf("Error");
o que significa que ambas as condições (x<2
e x>-2), devem ser verdadeiras para que
a condição completa seja verdadeira.
Este é um exemplo de um cálculo Booleano
condição3 = condição1
&& condição2;
if condição3
instrução;
operadores lógicos em C
&& | AND (E) |
|| | OR (Ou) |
Um outro operador lógico importante é o XOR, embora não
seja implementado nos cálculos Booleanos em C. a XOR b
significa "a ou b verdadeiros, mas não ambos!". Iremos utilizar
o XOR mais tarde nas operações lógicas com inteiros.
Outros operadores não implementados incluem o NAND e o NOR que são
importantes apenas ao nível electrónico, não sendo
muito úteis ao nível da programação.
Finalmente, existe um negador booleano !. Significa obter o oposto;
Se a é falso (0), !a é verdeiro (1), e
vice versa. Enquanto && e || necessitam de dois
operandos (por exemplo a || b), ! necessita apenas de um (!a).
Com estes operadores podemos calcular todas as condições
possíveis que precisemos.
Aqui estão as tabelas completas ("tabelas de verdade") dos cálculos
para os quatro operadores utilizados nas linguagens de programação
modernas.
|
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
a = 1;
b = -2;
c = 3;
d = 3;
if (a>0)
printf("TRUE");
else
printf("FALSE");
(a>0)
TRUE
(b>0)
FALSE
(a>0) && (b>0)
FALSE
(a>0) || (b>0)
TRUE
!(a>0)
FALSE
(! (a>0)) || (b>0)
FALSE
(2==b) || (!(2==b)) TRUE
operation | C |
AND |
|
OR |
|
XOR |
|
NOT |
|
Com esta convenção, as tabelas de verdade para a álgebra booleana bit-a-bit (bit-wise) ficam assim:
|
|
|
|
|
Como exemplo, vamos imaginar que queremos calcular 49 OR 24.
Primeiro, temos que converter estes números para o sistema binário (ver aula 3): 49 = 1*32 + 1*16 + 0*8 + 0*4 + 0*2 + 1*1 = 110001 24 = 0*32 + 1*16 + 1*8 + 0*4 + 0*2 + 0*1 = 011000 Depois, fazemos os cálculos bit-a-bit com as convenções da tabela de verdade de cima (1 OR 1 = 1, 1 OR 0 = 1, 0 OR 1 = 1, 0 OR 0 = 0), o que dará 111001 Finalmente, convertemos o resultado para o sistema decimal 111001 = 1*32 + 1*16 + 1*8 + 0*4 + 0*2 + 1*1 = 57 Na tabela ao lado, são exemplicadas também as outras operações com os números 49 e 24. |
main()
// outputs the lectures to follow
on basis of year
{
int ano;
printf("From what year
are you?\n");
scanf("%d", &ano);
if (ano==1)
printf("primeiro
ano: MAT-1, CALC-1\n");
else
if (ano==2)
printf("segundo ano: INF, LIN-ALG\n");
else
if (ano==3)
printf("terceiro ano: ELEC, FYS\n");
else
if (ano==4)
printf("quarto ano: QUI, MAT-2\n");
else
if (ano==5)
printf("quinto ano: PROJECTO\n");
else
printf(">5: AINDA NAO ACABOU?\n");
}
(De notar a estrutura do programa, com indentações. Reparar
também na ausência de ; antes de todos os else).
Este programa irá correr sem qualquer problema
From what year are you?
1
primeiro ano: MAT-1, CALC-1
From what year are you?
4
quarto ano: QUI, MAT-2
Apesar disso, a sua estrutura não é muito legível.
Para tornar o programa melhor (mais legível) podemos utilizar a
instrução switch. Enquanto
em "if (condição) instrução1;"
a condição é forçosamente do tipo boolena (verdeiro
ou falso), com o switch podemos utilizar
qualquer um dos tipos de variáveis que têm valores discretos
(em contraste com as variáveis floating point que não têm
valores discretos).
switch (expressão)
{ case valor1: instrução1; break; case valor2: instrução2; break; | case valorN: instruçãoN; break; default: instruçãoE; } |
A expressão tem que resultar
num valor de um tipo contável (por exemplo: int, long
int, mas também char. Não pode ser, por exemplo,
float).
Tal pode ser uma simples variável ou um cálculo que resulte
num valor. Os valores valor1 a valorN
têm que ser do mesmo tipo, mas não podem conter expressões
ou variáveis; têm que ser do tipo constant (constante).
A palavra reservada "default" significa que será executada esta
instrução se a expressão
não resultar em nenhum dos valores valor1..
valorN.
A instrução break
força o programa a saltar para o fim do ciclo (loop) (um ciclo de
switch neste caso).
Como exemplo, segue-se o programa anterior reescristo para utilizar
a instrução switch:
main()
// same program as above, but
with switch statement
{
int ano;
printf("From what year
are you?\n");
scanf("%d", &ano);
swicth (ano)
{
case 1: printf("primeiro
ano: MAT-1, CALC-1\n");
break;
case 2: printf("segundo
ano: INF, LIN-ALG\n");
break;
case 3: printf("terceiro
ano: ELEC, FYS\n");
break;
case 4: printf("quarto
ano: QUI, MAT-2\n");
break;
case 5: printf("quinto
ano: PROJECTO\n")
break;
default: printf(">5:
AINDA NAO ACABOU?\n");
}
}
Este programa terá o mesmo output que o programa anterior, mas é muito mais legível.