Aprenda Programação: Operações Lógicas e Álgebra Booleana
Créditos para a imagem: Imagem criada pelo autor usando o programa Spectacle.
Pré-Requisitos
Na introdução sobre ambientes de desenvolvimento, indiquei Python, Lua e JavaScript como boas escolhas de linguagens de programação para iniciantes. Posteriormente, comentei sobre GDScript como opção para pessoas que tenham interesse em programar jogos digitais ou simulações. Para as atividades de introdução a programação, você precisará de, no mínimo, um ambiente de desenvolvimento configurado em uma das linguagens anteriores.
Caso queira experimentar programação sem configurar um ambiente, você pode usar um dos editores online que criei:
Contudo, eles não possuem todos os recursos dos interpretadores para as linguagens. Assim, cedo ou tarde, você precisará configurar um ambiente de desenvolvimento. Caso precise configurar um, confira os recursos a seguir.
Assim, se você tem um Ambiente Integrado de Desenvolvimento (em inglês, Integrated Development Environment ou IDE) ou a combinação de editor de texto com interpretador, você está pronto para começar. Os exemplos assumem que você saiba executar código em sua linguagem escolhida, como apresentado nas páginas de configuração.
Caso queira usar outra linguagem, a introdução provê links para configuração de ambientes para as linguagens C, C++, Java, LISP, Prolog e SQL (com SQLite). Em muitas linguagens, basta seguir os modelos da seção de experimentação para adaptar sintaxe, comandos e funções dos trechos de código. C e C++ são exceções, por requerem o uso de ponteiros para acesso à memória.
Lógica e Aritmética
Como comentado em Aritmética e Matemática Básica, um dos componentes do processador chama-se Unidade Lógico-Aritmética (ULA em Português, ou Arithmetic Logic Unit ou ALU, em Inglês). A parte aritmética da programação em alto nível já foi apresentada, assim como operações relacionais para os primeiros resultados lógicos.
Resta, agora, a introdução de operações lógicas básicas. Embora elas também possam ser feitas em baixo nível, de forma bit-a-bit (bitwise), esta introdução aborda o uso em alto nível, por meio de valores lógicos e combinações de operadores relacionais.
Álgebra de Boole ou Álgebra Booleana
Existem dois valores na álgebra de Boole:
Verdadeiro
(True
) ou1
;Falso
(False
) ou0
.
Existem três operações principais em álgebra booleana:
- Conjunção, também chamada de
e
(and
), tem o símbolo (por exemplo, ); - Disjunção, também chamada de
ou
(or
), tem o símbolo (por exemplo, ); - Negação, também chamada de
não
(not
), tem o símbolo (por exemplo, ).
Algumas linguagens também definem um operador chamado ou-exclusivo, por vezes chamado de xou
(xor
), tem o símbolo (por exemplo, ).
Operações lógicas são tão freqüentes que você provavelmente memorizará os resultado pelo uso. Contudo, sempre é possível referenciar os valores, caso necessário.
Tabelas Verdade
Os resultados de operações lógicas são sintetizados em tabelas chamadas tabelas verdade (truth tables). Uma tabela verdade fornece resultados de uma expressão lógica para todas as combinações possíveis de valores lógicos para todas as variáveis. Em outras palavras se existir:
- Uma variável para inspecionar, considera-se o resultado para entrada
Falso
e para a entradaVerdadeiro
; - Duas variáveis: considera-se as combinações
Falso OP Falso
,Falso OP Verdadeiro
,Verdadeiro OP Falso
,Verdadeiro OP Verdadeiro
. - Três variáveis:
OP Falso Falso Falso
;OP Falso Falso Verdadeiro
;OP Falso Verdadeiro Falso
;OP Falso Verdadeiro Verdadeiro
;OP Verdadeiro Falso Falso
;OP Verdadeiro Falso Verdadeiro
;OP Verdadeiro Verdadeiro Falso
;OP Verdadeiro Verdadeiro Verdadeiro
.
- variáveis: todas as possíveis combinações de
Verdadeiro
eFalso
.
Para programação, os principais operadores serão unários ou binários. Ou seja, eles terão 2 ou 4 possíveis resultados, respectivamente.
Ou (Or)
O operador ou
resulta em Verdadeiro
caso ao menos um dos valores considerados seja Verdadeiro
.
Falso | Falso | Falso |
Falso | Verdadeiro | Verdadeiro |
Verdadeiro | Falso | Verdadeiro |
Verdadeiro | Verdadeiro | Verdadeiro |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
É importante notar que o ou
lógico não corresponde ao "ou" usando popularmente, que normalmente sugere alternativas excludentes.
No ou
lógico, Verdadeiro ou Verdadeiro
resulta em Verdadeiro
.
Para uma variação mais próxima do uso popular, pode-se usar o ou-exclusivo.
Para um exemplo de ou
lógico, pode-se considerar a seguinte pergunta: você gosta de programar ou de escrever?
- Se você não gosta de programar, nem de escrever, a resposta é
Falso
; - Se você não gosta de programar, mas gosta de escrever, a resposta é
Verdadeiro
; - Se você gosta de programar, mas não gosta de escrever, a resposta é
Verdadeiro
; - Se você gosta de programar e também gosta de escrever, a resposta é
Verdadeiro
.
E (And)
O operador e
resulta em Verdadeiro
apenas caso ambos os operandos considerados tenham valor lógico Verdadeiro
.
Em outras palavras, basta que um valor de operando seja Falso
para que o resultado da expressão também seja Falso
.
Falso | Falso | Falso |
Falso | Verdadeiro | Falso |
Verdadeiro | Falso | Falso |
Verdadeiro | Verdadeiro | Verdadeiro |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Para um exemplo de e
lógico, pode-se considerar uma pergunta similar à feita para ou
: você gosta de programar e de escrever?
- Se você não gosta de programar, nem de escrever, a resposta é
Falso
; - Se você não gosta de programar, mas gosta de escrever, a resposta é
Falso
; - Se você gosta de programar, mas não gosta de escrever, a resposta é
Falso
; - Se você gosta de programar e também gosta de escrever, a resposta é
Verdadeiro
.
Não (Not)
O operador não
inverte o valor lógico fornecido como entrada.
Verdadeiro
resulta em Falso
; Falso
resulta em Verdadeiro
.
Falso | Verdadeiro |
Verdadeiro | Falso |
0 | 1 |
1 | 0 |
Para um exemplo de não
lógico, pode-se considerar uma pergunta similar à feita para ou
: você não gosta de programar?
- Se você gosta de programar, a resposta é
Falso
, porque o resultado é invertido. Isso pode ser um pouco confuso. O motivo é que, no caso, a variável égosta_de_programar
. Se você gosta de programar,gosta_de_programar = Verdadeiro
. Portanto,não gosta_de_programar == Falso
, pois é o resultado invertido degosta_de_programar
. - Se você não gosta de programar, a resposta é
Verdadeiro
.
Perguntas feitas com não
são confusas para o cotidiano, mas serão úteis para programação.
Para facilitar a interpretação, você pode imaginar que está perguntando o contrário.
Como no exemplo, também é possível pensar na resposta para a questão afirmativa (como um resultado intermediário em uma variável) e inverter a resposta.
Xou (Xor)
O operador xou
é uma variação do ou
cujo resultado é Verdadeiro
apenas caso os valores lógicos dos operandos sejam diferentes.
Falso | Falso | Falso |
Falso | Verdadeiro | Verdadeiro |
Verdadeiro | Falso | Verdadeiro |
Verdadeiro | Verdadeiro | Falso |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
A expressão é logicamente equivalente () a:
Em pseudocódigo: p xou q == ((p ou q) e (não (p e q)))
.
Assim, caso a linguagem de programação não forneça um operador para xou
, é possível criar uma expressão equivalente usando o pseudocódigo anterior.
Para um exemplo de xou
lógico, pode-se considerar a mesma pergunta feita para ou
: você gosta de programar ou de escrever, mas não gosta de ambos?
- Se você não gosta de programar, nem de escrever, a resposta é
Falso
; - Se você não gosta de programar, mas gosta de escrever, a resposta é
Verdadeiro
; - Se você gosta de programar, mas não gosta de escrever, a resposta é
Verdadeiro
; - Se você gosta de programar e também gosta de escrever, a resposta é
Falso
.
Equivalências Lógicas
Uma equivalência lógica corresponde a uma expressão que pode ser substituída por uma outra mantendo todos os resultados iguais. Em outras palavras, ambas as expressões de uma equivalência lógica possuem a mesma tabela verdade.
A tabela a seguir relaciona as principais equivalências lógicas.
Nome | Expressão | Expressão Equivalente |
---|---|---|
Dupla negação | não não p | p |
Identidade | p e Verdadeiro | p |
p ou Falso | p | |
Dominação | p e Falso | Falso |
p ou Verdadeiro | Verdadeiro | |
Idempotência | p e p | p |
p ou p | p | |
Negação | p e (não p) | Falso |
p ou (não p) | Verdadeiro | |
Comutatividade | p e q | q e p |
p ou q | q ou p | |
Associatividade | (p e q) e r | p e (q e r) |
(p ou q) ou r | p ou (q ou r) | |
Propriedade distributiva | (p e q) ou (p e r) | p e (q ou r) |
(p ou q) e (p ou r) | p ou (q e r) | |
Absorção | p e (p ou q) | p |
p ou (p e q) | p | |
Leis De Morgan | (não p) e (não q) | não (p ou q) |
(não p) ou (não q) | não (p e q) |
É interessante notar que muitas delas são similares a equivalências usadas em Matemática para operações aritméticas.
A tabela permite gerar expressões equivalentes mais simples (ou alternativas).
Por exemplo, escrever p ou Verdadeiro
é redundante, porque Verdadeiro
sempre é Verdadeiro
, ou seja, o resultado do ou
sempre será Verdadeiro
, tornando p
supérfluo.
De fato, a equivalência lógica chamada dominação expressa o mesmo resultado.
Da mesma forma, escrever p ou Falso
equivale a escrever apenas p
(pela identidade), pois Falso
sempre será Falso
.
Pelo uso do operador ou
, o resultado sempre dependerá de p
.
Se p
for Verdadeiro
, a expressão terá resultado Verdadeiro
.
Caso contrário, o resultado será Falso
.
Caso tenha dúvidas ou queira entender as equivalências, você pode escrever a tabela verdade de cada expressão. Outra alternativa é escrever um código para analisar os resultados (e, caso queira, compará-los automaticamente usando operações relacionais).
As relações anteriores são as mais usuais em programação, embora existam outras. Também existem inferências lógicas; como curiosidade, uma das regras de inferência mais famosas chama-se modus ponens.
Portas Lógicas
Computadores funcionam por meio de operações lógicas. Além de operações lógicas propriamente ditas, operações lógicas permitem que computadores realizem operações aritméticas. Por mais incrível que possa parecer, a memória de computadores também pode ser definida usando operações lógicas.
Em outras palavras, é possível construir computadores usando apenas operações lógicas. Por comodidade, existem circuitos prontos para construção de máquinas digitais chamados de portas lógicas.
A memória de computadores pode ser criada, dentre outros, como combinações de portas lógicas não
e and
(ou como a combinação de ambas, chamada porta NAND); também é possível criá-la usando portas lógicas não
e or
(ou com a combinação, chamada porta NOR).
Caso queira saber mais, procure por flip-flop.
Caso queira conhecer sobre como computadores fazem operações matemáticas usando operações lógicas, um bom ponto de partida é conhecer sobre um circuito somador, que pode fazer somas de bits.
Operadores Lógicos em Programação
Atividades de programação normalmente não chegam a um nível baixo o suficiente para operar com portas lógicas, embora seja possível. Existem linguagens de programação para especificação de hardware, que permitem criar circuitos complexos como combinações de circuitos mais simples (que, no nível mais baixo, são combinações de portas lógicas).
Embora seja algo interessante, o uso de operações lógicas em linguagens de programação de software é muito mais simples.
Fluxogramas: Flowgorithm
Assim como operadores relacionais, operadores lógicos em Flowgorithm podem ser usados em expressões. Neste momento, em Atribuição (Assign) ou como Saída (Output).
Valores lógicos em Flowgorithm são true
, para Verdadeiro
, e false
, para Falso
.
Flowgorithm permite usar and
ou &&
para o operador lógico e
; or
ou ||
, para o operador lógico ou
; not
or !
, para o operador lógico não
.
Você pode optar pelo que preferir; o exemplo adotará os nomes por extenso.
O trecho de código a seguir contém a transcrição do texto da imagem.
Principal
Lógico eBooleano
eBooleano = true and false
Saída eBooleano
Lógico ouBooleano
ouBooleano = true or false
Saída ouBooleano
Lógico naoBooleano
naoBooleano = not true
Saída naoBooleano
Inteiro numero
numero = 64
Lógico numeroPositivoEPar
numeroPositivoEPar = (numero > 0) and (numero % 2 == 0)
Saída numeroPositivoEPar
Caracteres nomeMinusculas
nomeMinusculas = "Franco"
Lógico nomeEFrancoOuGarcia
nomeEFrancoOuGarcia = (nomeMinusculas == "franco") or (nomeMinusculas == "garcia")
Saída nomeEFrancoOuGarcia
Fim
Como Flowgorithm não fornece uma subrotina para conversão de caixas, o programa assume o uso de letras minúsculas para o nome.
Linguagens de Programação Visual: Scratch
Em Scratch, operadores lógicos estão na aba lateral Operadores (Operators), disponíveis nos blocos _
e _
(_
and _
), _
ou _
(_
or _
), e não _
(not _
).
Uma limitação da linguagem é a falta de constantes para os valores lógicos Verdadeiro
e Falso
.
Contudo, como muitos valores lógicos resultam de operadores relacionais, a limitação nem sempre é um problema para o aprendizado.
Uma alternativa é usar um bloco não _
vazio como Verdadeiro
, e usar um bloco _
e _
vazio com Falso
.
A alternativa funciona porque, em Scratch, o bloco não _
vazio resulta true
, enquanto o bloco _
e _
vazio resulta false
.
O uso é confuso e (admitidamente) uma gambiarra, mas serve para programas simples a título de ilustração.
Infelizmente, criar uma variável chamada Verdadeiro
e uma variável chamada Falso
com os resultados das expressões não funciona, pois os blocos com operadores lógicos não permitem o uso direto de variáveis.
Como Scratch não é sensível à caixa, a implementação não converte o nome para letras minúsculas para a comparação.
Linguagens de Programação Textual: JavaScript, Python, Lua e GDScript
JavaScript define &&
para e
, ||
para ou
, e !
para não
.
Python e Lua definem and
para e
, or
para ou
, e not
para não
.
GDScript permite usar ambos os estilos; você pode escolher o que preferir.
Pessoalmente, eu acho mais rápido digitar o nome que usar os símbolos, mas é questão de preferência.
var e_booleano = true && false
console.log(e_booleano)
var ou_booleano = true || false
console.log(ou_booleano)
var nao_booleano = !true
console.log(nao_booleano)
var numero = 64
var numero_positivo_e_par = (numero > 0) && (numero % 2 === 0)
console.log(numero_positivo_e_par)
var nome = "Franco"
var nome_minusculas = nome.toLowerCase()
var nome_e_franco_ou_garcia = (nome_minusculas === "franco") || (nome_minusculas === "garcia")
console.log(nome_e_franco_ou_garcia)
e_booleano = True and False
print(e_booleano)
ou_booleano = True or False
print(ou_booleano)
nao_booleano = not True
print(nao_booleano)
numero = 64
numero_positivo_e_par = (numero > 0) and (numero % 2 == 0)
print(numero_positivo_e_par)
nome = "Franco"
nome_minusculas = nome.lower()
nome_e_franco_ou_garcia = (nome_minusculas == "franco") or (nome_minusculas == "garcia")
print(nome_e_franco_ou_garcia)
local e_booleano = true and false
print(e_booleano)
local ou_booleano = true or false
print(ou_booleano)
local nao_booleano = not true
print(nao_booleano)
local numero = 64
local numero_positivo_e_par = (numero > 0) and (numero % 2 == 0)
print(numero_positivo_e_par)
local nome = "Franco"
local nome_minusculas = nome:lower()
local nome_e_franco_ou_garcia = (nome_minusculas == "franco") or (nome_minusculas == "garcia")
print(nome_e_franco_ou_garcia)
extends Node
func _init():
var e_booleano = true and false # ou true && false
print(e_booleano)
var ou_booleano = true or false # true || false
print(ou_booleano)
var nao_booleano = not true # ou !true
print(nao_booleano)
var numero = 64
var numero_positivo_e_par = (numero > 0) and (numero % 2 == 0)
print(numero_positivo_e_par)
var nome = "Franco"
var nome_minusculas = nome.to_lower()
var nome_e_franco_ou_garcia = (nome_minusculas == "franco") or (nome_minusculas == "garcia")
print(nome_e_franco_ou_garcia)
Exemplos
Operadores lógicos são simples quando considerados individualmente. Quando combinados, eles permitem resolver problemas mais complexos, que poderiam ser impossíveis sem eles.
Combinando Valores Lógicos
Por exemplo, nem sempre é possível relacionar múltiplas variáveis sem o uso de um operador lógico. Por vezes é possível para fórmulas físicas ou matemática, mas o que fazer para outros problemas?
Gosto de...
Pessoas normalmente tem mais de um interesse. De que você gosta? De que você não gosta?
Verdadeiro ou falso? Você gosta de:
- Pizza?
- Chocolate?
- Programação?
- Cães?
- Gatos?
As respostas anteriores podem ser combinadas para saber mais sobre você. Por exemplo, como informar o computador se você:
- Gosta de pizza e chocolate?
- Gosta de chocolate ou programação?
- Gosta de pizza e cães, mas não gosta de gatos?
- Gosta de programação ou gatos, mas não gosta de cães ou pizza? Essa pergunta pode ser ambígua. Programação não permite ambigüidades. Considere "mas não (gosta de cães ou pizza)" ao invés de "mas (não gosta de cães) ou gosta de pizza".
As respostas requerem o uso de operadores lógicos. Modifique os valores das variáveis e descubra as respostas. Com cinco definições de variáveis, é possível criar várias combinações de interesses.
let gosta_de_pizza = false
let gosta_de_chocolate = false
let gosta_de_programacao = false
let gosta_de_caes = false
let gosta_de_gatos = false
console.log("Gosta de pizza e chocolate? ", gosta_de_pizza && gosta_de_chocolate)
console.log("Gosta de chocolate ou programação? ", gosta_de_chocolate || gosta_de_programacao)
console.log("Gosta de pizza e cães, mas não gosta de gatos? ", (gosta_de_pizza && gosta_de_caes) && (!gosta_de_gatos))
console.log("Gosta de programação ou gatos, mas não gosta de cães ou pizza? ", (gosta_de_programacao || gosta_de_gatos) && (!(gosta_de_caes || gosta_de_pizza)))
gosta_de_pizza = False
gosta_de_chocolate = False
gosta_de_programacao = False
gosta_de_caes = False
gosta_de_gatos = False
print("Gosta de pizza e chocolate? ", gosta_de_pizza and gosta_de_chocolate)
print("Gosta de chocolate ou programação? ", gosta_de_chocolate or gosta_de_programacao)
print("Gosta de pizza e cães, mas não gosta de gatos? ", (gosta_de_pizza and gosta_de_caes) and (not gosta_de_gatos))
print("Gosta de programação ou gatos, mas não gosta de cães ou pizza? ", (gosta_de_programacao or gosta_de_gatos) and (not (gosta_de_caes or gosta_de_pizza)))
local gosta_de_pizza = false
local gosta_de_chocolate = false
local gosta_de_programacao = false
local gosta_de_caes = false
local gosta_de_gatos = false
print("Gosta de pizza e chocolate? ", gosta_de_pizza and gosta_de_chocolate)
print("Gosta de chocolate ou programação? ", gosta_de_chocolate or gosta_de_programacao)
print("Gosta de pizza e cães, mas não gosta de gatos? ", (gosta_de_pizza and gosta_de_caes) and (not gosta_de_gatos))
print("Gosta de programação ou gatos, mas não gosta de cães ou pizza? ", (gosta_de_programacao or gosta_de_gatos) and (not (gosta_de_caes or gosta_de_pizza)))
extends Node
func _init():
var gosta_de_pizza = false
var gosta_de_chocolate = false
var gosta_de_programacao = false
var gosta_de_caes = false
var gosta_de_gatos = false
print("Gosta de pizza e chocolate? ", gosta_de_pizza and gosta_de_chocolate)
print("Gosta de chocolate ou programação? ", gosta_de_chocolate or gosta_de_programacao)
print("Gosta de pizza e cães, mas não gosta de gatos? ", (gosta_de_pizza and gosta_de_caes) and (not gosta_de_gatos))
print("Gosta de programação ou gatos, mas não gosta de cães ou pizza? ", (gosta_de_programacao or gosta_de_gatos) and (not (gosta_de_caes or gosta_de_pizza)))
O exemplo mostra como operadores lógicos permitem a construção de expressões mais complexas para fazer constatações sobre o estado de um programa.
Operadores Aritméticos, Relacionais e Lógicos
Para tirar conclusões sobre vários resultados aritméticos, pode-se usar operadores relacionais e lógicos. Tanto operadores relacionais quanto lógicos fornecem valores lógicos como respostas.
Para um exemplo, pode-se considerar a desigualdade triangular. A desigualdade triangular afirma que o tamanho de um lado de um triângulo sempre é menor que a soma dos outros dois lados.
Em símbolos, para um triângulo com lados , e :
- ;
- ;
- .
Dados três lados, eles formam um triângulo? Você pode escrever um programa para responder à questão, analisando valores fornecidos para os lados.
let a = 3.0
let b = 4.0
let c = 5.0
let triangulo_valido = (a < b + c) && (b < a + c) && (c < a + b)
console.log(triangulo_valido)
a = 3.0
b = 4.0
c = 5.0
triangulo_valido = (a < b + c) and (b < a + c) and (c < a + b)
print(triangulo_valido)
local a = 3.0
local b = 4.0
local c = 5.0
local triangulo_valido = (a < b + c) and (b < a + c) and (c < a + b)
print(triangulo_valido)
extends Node
func _init():
var a = 3.0
var b = 4.0
var c = 5.0
var triangulo_valido = (a < b + c) and (b < a + c) and (c < a + b)
print(triangulo_valido)
Que tal melhorar a solução? Lados devem ser números positivos.
Para assegurar que a resposta apenas admita valores positivos para cada lado, pode-se verificar cada um deles usando uma comparação (por exemplo, a > 0
) e combinar as respostas usando o operador e
.
Em seguida, basta combinar a verificação de lados positivos com a verificação de comprimentos.
Se ambos os resultados sejam verdadeiros, a resposta será Verdadeiro
.
Caso qualquer um dos resultados seja Falso
, a resposta será Falsa
-- ou seja, os lados não formam um triângulo.
let a = 3.0
let b = 4.0
let c = 5.0
let lados_positivos = (a > 0.0) && (b > 0.0) && (c > 0.0)
let lados_validos = (a < b + c) && (b < a + c) && (c < a + b)
let triangulo_valido = lados_positivos && lados_validos
console.log(triangulo_valido)
a = 3.0
b = 4.0
c = 5.0
lados_positivos = (a > 0.0) and (b > 0.0) and (c > 0.0)
lados_validos = (a < b + c) and (b < a + c) and (c < a + b)
triangulo_valido = lados_positivos and lados_validos
print(triangulo_valido)
local a = 3.0
local b = 4.0
local c = 5.0
local lados_positivos = (a > 0.0) and (b > 0.0) and (c > 0.0)
local lados_validos = (a < b + c) and (b < a + c) and (c < a + b)
local triangulo_valido = lados_positivos and lados_validos
print(triangulo_valido)
extends Node
func _init():
var a = 3.0
var b = 4.0
var c = 5.0
var lados_positivos = (a > 0.0) and (b > 0.0) and (c > 0.0)
var lados_validos = (a < b + c) and (b < a + c) and (c < a + b)
var triangulo_valido = lados_positivos and lados_validos
print(triangulo_valido)
Técnica Alternativa
Antes de prosseguir, existe uma técnica alternativa interessante para resolver o problema. Você pode alterar um pouco a solução e calcular novos valores lógicos baseando-se em resultados anteriores, como feito em aritmética. Por exemplo, em JavaScript:
let a = 3.0
let b = 4.0
let c = 5.0
let triangulo_valido = a > 0.0
triangulo_valido = triangulo_valido && (b > 0.0)
triangulo_valido = triangulo_valido && (c > 0.0)
triangulo_valido = triangulo_valido && (a < b + c)
triangulo_valido = triangulo_valido && (b < a + c)
triangulo_valido = triangulo_valido && (c < a + b)
console.log(triangulo_valido)
No caso, o resultado foi calculado passo a passo atualizando o valor da última resposta, usando-se o valor da última resposta para incluir a nova verificação.
Algumas linguagens de programação, como JavaScript, fornecem, inclusive, um operador de atribuição especializado para realizar a operação anterior, como &&=
(também exite um para o ou
: ||=
, embora não exista para o não
, pois o operador corresponde ao usado para diferença).
let a = 3.0
let b = 4.0
let c = 5.0
let triangulo_valido = a > 0.0
triangulo_valido &&= (b > 0.0)
triangulo_valido &&= (c > 0.0)
triangulo_valido &&= (a < b + c)
triangulo_valido &&= (b < a + c)
triangulo_valido &&= (c < a + b)
console.log(triangulo_valido)
O código é um pouco estranho e não muito usual, mas é equivalente ao exemplo anterior.
Deve-se notar, contudo, que, caso a expressão misturasse e
, ou
e não
, a solução ficaria mais complexa, pois ela deveria considerar todos os agrupamentos corretos e regras de precedência de operadores.
Assim, mesmo sendo possível, eu recomendaria seguir a implementação original (por exemplo, usando lados_positivos
, lados_validos
e triangulo_valido
) para uma solução mais fácil de ler e entender.
Após a introdução de estruturas de condição, será possível, inclusive, escrevê-la de forma diferente.
Construção de Tabela Verdade
Para criar uma tabela verdade, pode-se usar uma linguagem de programação para computar os possíveis resultados de uma expressão lógica.
console.log("false && false: ", false && false)
console.log("false && true: ", false && true)
console.log("true && false: ", true && false)
console.log("false && false: ", true && true)
console.log("false || false: ", false || false)
console.log("false || true: ", false || true)
console.log("true || false: ", true || false)
console.log("false || false: ", true || true)
console.log("! false:", !false)
console.log("! true:", !true)
print("False and False: ", False and False)
print("False and True: ", False and True)
print("True and False: ", True and False)
print("False and False: ", True and True)
print("False or False: ", False or False)
print("False or True: ", False or True)
print("True or False: ", True or False)
print("False or False: ", True or True)
print("not False:", not False)
print("not True:", not True)
print("false and false: ", false and false)
print("false and true: ", false and true)
print("true and false: ", true and false)
print("false and false: ", true and true)
print("false or false: ", false or false)
print("false or true: ", false or true)
print("true or false: ", true or false)
print("false or false: ", true or true)
print("not false:", not false)
print("not true:", not true)
extends Node
func _init():
print("false and false: ", false and false)
print("false and true: ", false and true)
print("true and false: ", true and false)
print("false and false: ", true and true)
print("false or false: ", false or false)
print("false or true: ", false or true)
print("true or false: ", true or false)
print("false or false: ", true or true)
print("not false:", not false)
print("not true:", not true)
print("false && false: ", false && false)
print("false && true: ", false && true)
print("true && false: ", true && false)
print("false && false: ", true && true)
print("false || false: ", false || false)
print("false || true: ", false || true)
print("true || false: ", true || false)
print("false || false: ", true || true)
print("! false:", !false)
print("! true:", !true)
O processo poderá, inclusive, ser automatizado após a introdução de estruturas de repetição.
Teste de Equivalência Lógica
Quando se comentou sobre o operador xou
(xor
), apresentou-se uma equivalência lógica usando ou
, e
e não
.
Que tal criar uma tabela verdade para verificar se, de fato, ?
console.log("p xor q = ?")
let p = false
let q = false
let xor = ((p || q) && (!(p && q)))
console.log(p, " xor ", q, " = ", xor)
q = true
xor = ((p || q) && (!(p && q)))
console.log(p, " xor ", q, " = ", xor)
p = true
q = false
xor = ((p || q) && (!(p && q)))
console.log(p, " xor ", q, " = ", xor)
q = true
xor = ((p || q) && (!(p && q)))
console.log(p, " xor ", q, " = ", xor)
print("p xor q = ?")
p = False
q = False
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
q = True
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
p = True
q = False
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
q = True
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
print("p xor q = ?")
local p = false
local q = false
local xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
q = true
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
p = true
q = false
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
q = true
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
extends Node
func _init():
print("p xor q = ?")
var p = false
var q = false
var xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
q = true
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
p = true
q = false
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
q = true
xor = ((p or q) and (not (p and q)))
print(p, " xor ", q, " = ", xor)
Deve-se notar que variáveis que não foram alteradas mantém o último valor atribuído. Assim, o resultado do programa será algo como:
p xor q = ?
false xor false = false
false xor true = true
true xor false = true
true xor true = false
Comparando-se o resultado de cada linha com a linha equivalente da tabela, pode-se observar que, de fato, as expressões são equivalentes.
Novos Itens para Seu Inventário
Ferramentas:
- Tabelas verdade.
Habilidades:
- Uso de conjunções;
- Uso de disjunções;
- Uso de negações;
- Criação de expressões lógicas.
Conceitos:
- Conjunções ou
e
; - Disjunções ou
ou
; - Negação ou
não
; - Equivalências lógicas.
Recursos de programação:
- Operadores lógicos.
Pratique
Crie uma variável chamada
fruta
. Atribua um valor ou solicite a entrada de um nome de fruta. Afruta
é uma banana, uma maçã ou uma uva?No exercício a anterior, a
fruta
não é banana, maçã ou uva? Neste caso, pode-se usar a resposta anterior com o operadornão
para inverter a resposta.Crie uma variável chamada
numero
. O número é ímpar? O número é ímpar e é igual a 7? O número é ímpar e negativo? O número é ímpar, positivo e múltiplo de 17? O número é 4? Caso não seja, ele é negativo e múltiplo de 3?Crie variáveis que armazenem valores lógicos com seus interesses. Por exemplo, gosto ou não gosto de:
- Estudar;
- Culinária;
- Esportes;
- Programação;
- Jogos;
- Conversar.
Crie expressões lógicas como combinações das variáveis.
Defina quatro variáveis para credenciais de acesso:
- Nome de usuário esperado;
- Senha esperada para o nome de usuário anterior;
- Nome de usuário fornecido;
- Senha fornecida.
Com os dados fornecidos, a pessoa conseguiria acessar o sistema? Isto é, seria o acesso liberado para ela?
Crie algumas variáveis com notas de 0.0 até 10.0 para livros, filmes, músicas, jogos, linguagens de programação, ou qualquer outro item de seu interesse. Considere que o ponto represente a vírgula decimal. Em seguida, verifique quais itens teriam notas consideradas medianas, assumindo que a nota mediana fique entre 5.0 (inclusive) e abaixo de 6.5 (não inclusive) -- isto é, a nota pertence ao intervalo [5.0, 6.5[ (lê-se intervalo fechado para 5.0, aberto para 6.5).
Por exemplo, um filme com nota 5.0 é classificado como mediano. Uma música com nota 6.21 também, assim como um livro classificado com 6.4999999. Um jogo com nota 6.5 não é considerado mediano.
Para o exercício anterior, considere, agora, que:
- Itens com notas entre [0.0, 5.0[ sejam classificados como ruins;
- Itens com notas entre [6.5, 8.0[ sejam classificados como bons;
- Itens com notas entre [8.0, 10.0] sejam classificados como ótimos.
Escolha algumas combinações de variáveis e combine-as com operações lógicas. Por exemplo, assumindo que suas variáveis incluam suas notas para as linguagens
flowgorithm
,scratch
,python
,lua
,javascript
egdscript
adotadas nesta página:- Qualquer das variáveis anteriores é considerada ótima?
flowgorithm
ouscratch
são medianas?javascript
,python
elua
são boas?lua
é boa, mediana ou ótima?lua
não é ruim?- (
flowgorithm
oulua
) são (boas ou ótimas), mas (scratch
ejavacript
) são (ruins ou medianas)? - Não existe nenhum item ruim?
Próximos Passos
Com entrada, saída, operadores aritméticos, relacionais e lógicos já é possível resolver alguns problemas simples. Com os próximos conceitos, será possível começar a resolver problemas cada vez mais complexos, com validação para entrada e uso de saída mais sofisticada.
Em particular, todo programa até o momento foi executado de forma linear, isto é, a máquina seguiu as instruções na forma definida, sem pular nenhuma.
Com estruturas de condição, será possível escolher instruções para executar ou ignorar de acordo com o estado atual do programa. Para isso, operações relacionais e lógicas definirão condições para a escolha do próximo caminho a seguir.
- Introdução;
- Ponto de entrada e estrutura de programa;
- Saída (para console ou terminal);
- Tipos de dados;
- Variáveis e constantes;
- Entrada (para console ou terminal);
- Aritmética e Matemática básica;
- Operações relacionais e comparações;
- Operações lógicas e Álgebra Booleana;
- Estruturas de condição (ou condicionais ou de seleção);
- Subrotinas: funções e procedimentos;
- Estruturas de repetição (ou laços ou loops);
- Vetores (arrays), cadeias de caracteres (strings), coleções (collections) e estruturas de dados;
- Registros (structs ou records);
- Arquivos e serialização (serialization ou marshalling);
- Bibliotecas;
- Entrada em linha de comando;
- Operações bit-a-bit (bitwise operations);
- Testes e depuração.