Baixe o app para aproveitar ainda mais
Prévia do material em texto
Unidade 1. Introdução a computadores e linguagem de programação Desde suas primeiras aplicações no século passado, ficou claro que o computador mudaria para sempre nossas vidas. Os computadores, que antes eram grandes máquinas de calcular, passaram a fazer parte de nossa realidade no formato de desktops pessoais, tablets, smartphones e tantos outros. Deste modo, saber o que está dentro deles e como funcionam o ajudará a projetar, desenvolver e implementar aplicativos melhores, mais rápidos, mais baratos, mais eficientes e mais fáceis de usar. Durante a leitura deste material, você conhecerá um pouco da história dos computadores, além de sua arquitetura e como seus componentes interagem. Entenderá que um algoritmo é uma sequência lógica de instruções e que não se limita apenas à computação. Compreenderá o conceito de linguagem de programação, os principais paradigmas envolvidos e entenderá que essas linguagens foram criadas para dizer ao computador e aos elementos de sua arquitetura o que eles têm que fazer e quando têm que fazer. Bons estudos! AUTOR professor Ariel da Silva Dias OBJETIVOS DA UNIDADE • Compreender a arquitetura de um computador e os elementos que a compõem; • Compreender o conceito de bits e seus múltiplos; • Reconhecer a estrutura de um algoritmo e como implementá-lo; • Discutir sobre os diferentes paradigmas de programação. TÓPICOS DE ESTUDO Introdução a computadores e componentes // Arquitetura de um computador // Representação da informação no computador Desenvolvimento de algoritmos // Sintaxe de um algoritmo // Semântica de um algoritmo // Tipos de dados e convenções // Operações aritméticas Linguagens de programação // Paradigmas // Paradigma declarativo // Paradigma de programação orientada a eventos // Linguagens de baixo e de alto nível Introdução a computadores e componentes Desde muito cedo, em 300 a.C., na Babilônia (atual Iraque), as máquinas de contagem, conhecidas como ábacos, já eram utilizadas no senso e para outros tipos de cálculos. A primeira ferramenta de contagem acionada por engrenagem foi o relógio de cálculo de Schickard, inventado em 1623. Alguns anos depois, uma calculadora – capaz de adicionar, subtrair, multiplicar e dividir – foi desenvolvida pelo famoso estudioso Gottfried Wilhelm Leibniz, que também desenvolveu os números binários e muitas ideias importantes em filosofia e lógica. Em 1642, o filósofo e matemático Blaise Pascal, aos 19 anos, inventou a pascaline (Figura 1) como uma ajuda para o pai, que era cobrador de impostos. Pascal construiu 50 unidades dessa calculadora de função única acionada por engrenagem, cuja única funcionalidade era realizar adição. Entretanto, devido ao custo exorbitante, não conseguiu vender muitas dessas calculadoras. Outro fator da baixa venda dá-se porque elas realmente não eram tão precisas, afinal, naquela época, não era possível fabricar engrenagens com a precisão necessária. Note que estamos falando de uma “tecnologia” (assim era para a época) que durou até a era atual, pois nos painéis dos carros a parte do hodômetro do velocímetro usava o mesmo mecanismo que a Pascaline para incrementar a próxima roda após cada rotação completa da roda anterior. O alemão Gottfried Wilhelm Leibniz, poucos anos depois de Pascal, conseguiu construir uma calculadora de quatro funções – adição, subtração, multiplicação e divisão –, que foi batizada de contador de passos. Embora o contador empregasse o sistema de números decimais, Leibniz foi o primeiro a defender o uso do sistema de números binários, fundamental para a operação dos computadores modernos. Leibniz é considerado um grande filósofo, foi inventor do cálculo junto com Newton, mas morreu pobre e sozinho. Com o sistema binário, os inventores foram capazes de usar sistemas de cartões perfurados para os primeiros computadores eletrônicos. A International Business Machines (IBM) posteriormente adotaria essa tecnologia e a disponibilizaria para usos mais amplos. Para atender às demandas de orientação de mísseis durante a Segunda Guerra Mundial, a IBM e a Universidade de Harvard se uniram para criar o Harvard Mark I, um computador mecânico de um metro e oitenta de altura. Este foi o primeiro computador moderno. A Hewlett-Packard (HP), uma empresa de tecnologia iniciada em 1939, desenvolveu seu primeiro computador em 1966. O HP 2116A, como era chamado, era um controlador para vários instrumentos diferentes. Em 1974, a HP desenvolveu um sistema de processamento de memória que usava chips DRAM (Dynamic Random Access Memory Chips), em oposição aos núcleos magnéticos populares. O primeiro computador pessoal estava disponível em 1975: o computador MITAS Altair. Ele vinha em uma caixa e tinha que ser montado pelo comprador. Este foi o computador que inspirou Bill Gates, então calouro de Harvard, a mudar o rumo de sua carreira e criar a empresa chamada Microsoft. O primeiro computador da Apple, o Apple I, estava disponível um ano depois. ARQUITETURA DE UM COMPUTADOR A arquitetura do computador é uma especificação que detalha como o conjunto de padrões de tecnologia de software e hardware interagem para formar um sistema ou plataforma computacional. Em resumo, a arquitetura do computador se refere a como um sistema de computador é projetado e com quais tecnologias ele é compatível. Como vimos brevemente em sua história, o computador é uma máquina eletrônica que facilita a execução de qualquer tarefa. No computador, a CPU executa cada instrução fornecida em uma série de etapas. Essa série é chamada ciclo da máquina e é repetida para cada instrução. Um ciclo de máquina envolve buscar instruções, decodificar as instruções, transferir os dados e executar as instruções. Existem três categorias de arquitetura de computadores: Design do sistema: inclui todos os componentes de hardware do sistema, como processadores, unidade de processamento gráfico e acesso direto à memória. Ele também inclui controladores de memória, caminhos de dados, multiprocessamento e virtualização. Arquitetura do conjunto de instruções (ISA): é a linguagem de programação incorporada da unidade central de processamento. Ela define as funções e capacidades da CPU com base em qual programação pode executar ou processar. Isso inclui o tamanho da palavra, tipos de registro do processador, modos de endereçamento da memória, formatos de dados e o conjunto de instruções que os programadores usam. Microarquitetura: também conhecida como organização do computador, esse tipo de arquitetura define os caminhos dos dados, o processamento e o armazenamento dos dados, bem como a forma que eles devem ser implementados na ISA. Na história da computação, surgiram diversos tipos de arquiteturas de computador. Entretanto, a mais famosa, utilizada até hoje, é a arquitetura de Von Neumann, criada em 1946 por John Von Neumann (Figura 2). Figura 2. Arquitetura de Von Neumann. Conforme pode ser observado na Figura 2, o sistema computacional possui unidades básicas que ajudam o computador a executar operações. Veja a seguir: Unidade de entrada Conecta o ambiente externo ao sistema interno do computador. Ela fornece dados e instruções para o sistema do computador. Os dispositivos de entrada mais usados são teclado, mouse, fita magnética etc. A unidade de entrada executa as seguintes tarefas: aceita os dados e instruções do ambiente externo, converte- o em linguagem de máquina e fornece ao sistema computacional os dados convertidos. Unidade de saída Responsável por conectar o sistema interno do computador ao ambiente externo. Ela fornece os resultados de qualquer cálculo ou instruções para o mundo exterior. Alguns dispositivos de saída são impressoras e monitores. Unidade de memória ouarmazenamento Contém os dados e instruções. Ela também armazena os resultados intermediários antes de serem enviados para os dispositivos de saída ou para uso posterior. A unidade de memória ou armazenamento de um sistema de computador pode ser dividida em duas categorias: • Armazenamento primário: é um tipo volátil, com armazenamento temporário, usado para armazenar os dados que estão sendo executados no momento. Os dados são perdidos quando o computador é desligado. A RAM é usada como memória de armazenamento principal; • Armazenamento secundário: é um tipo não volátil, com armazenamento permanente de dados, sendo esta memória mais lenta e mais barata que a memória primária. Os dispositivos de memória secundária comumente usados são discos rígidos e CDs. Unidade lógica aritmética (ULA) Todos os cálculos são realizados na ULA do sistema computacional. Ela pode executar operações básicas, como adição, subtração, divisão, multiplicação etc. Sempre que são necessários cálculos, a unidade de controle transfere os dados da unidade de armazenamento para a ULA. Quando as operações são concluídas, o resultado é transferido de volta para a unidade de armazenamento. Unidade de controle Responsável por controlar todas as outras unidades do computador e por buscar as instruções na memória principal. Também é conhecida como sistema nervoso central do computador. Unidade central de processamento (UCP) A unidade de controle e a ULA são conhecidas como UCP (ou CPU para sigla em inglês de central processing unit). A UCP é o cérebro do sistema computacional. Ela executa as seguintes tarefas: realiza todas as operações, toma todas as decisões e controla todas as unidades do computador. REPRESENTAÇÃO DA INFORMAÇÃO NO COMPUTADOR A arquitetura do computador é composta de circuitos eletrônicos, que operam com sinais binários (0 e 1). A principal razão para esta arquitetura ser binária e não decimal é sua simplicidade e baixo custo de implementação. Nos projetos de circuitos computacionais são usados chips, que são compostos de um material semicondutor denominado transistor. Os transistores possuem a propriedade de conduzir energia elétrica apenas quando uma tensão conveniente é empregada em seus terminais. Sendo assim, os transistores são utilizados em um chaveamento como “liga-desliga”, sendo que, quando está ligado, é representado por 1, e, quando desligado, é representado por 0. O agrupamento de transistores permite outras funções lógicas. Como não é o objetivo deste livro se aprofundar nessas funções, por ora é suficiente saber que tudo o que é armazenado e processado no computador trata-se de um conjunto finito de 0s e 1s, e isso nos leva ao conceito de bits. // Conceito de bits A informação mais básica que um computador consegue compreender é o bit. Este termo é uma forma abreviada de dígito binário e possui apenas um dos dois valores: 0 ou 1. Se você olhar para um interruptor de luz, verá que ele é um mecanismo binário, pois ou está ligado ou desligado. A forma abreviada de um bit é uma letra minúscula b. Para ter certeza de que seu significado é entendido, você provavelmente deve usar a palavra inteira bit, pois, em geral, às vezes as pessoas usam indevidamente a letra minúscula b para byte. Nós, seres humanos, não conseguimos (ou temos alguma dificuldade) em pensar em termos de bits. Somente computadores possuem facilidade e a destreza ao trabalhar com eles. Portanto, os seres humanos foram criando, aos poucos, uma organização para interagir com o computador. É aí que entram os bytes e outras coleções de bits. // Bytes e seus múltiplos para coleção de bits Um byte (sua forma abreviada é um B maiúsculo) é uma unidade comum para agrupamentos de bits. Em uso geral, um byte é considerado uma sequência contígua de oito bits. Existem outros significados menos comuns para um byte, mas, para a sua formação, a sequência de oito bits é boa e será adotada neste livro. Em termos de conversão para uso humano, considere que oito bits podem representar 256 coisas diferentes. Começando com zero (a contagem por um computador geralmente começa em zero em vez de um), você obtém uma sequência como a seguir: • 00000000 = decimal 0 • 00000001 = decimal 1 • 00000010 = decimal 2 • 00000011 = decimal 3 • ... • 11111111 = decimal 255 Deste modo, você pode mapear os números inteiros de 0 a 255 em um byte, usar 256 bytes para representar 256 caracteres ASCII diferentes, usar 256 bytes para representar números hexadecimais de 0 a FF ou qualquer outro mapeamento definido por você. A capacidade de fazer esse mapeamento permite que os humanos interajam melhor com os computadores sem ter que pensar em binário. As coisas ficam complicadas quando os conjuntos de bytes começam a aumentar; é aí que surgem os múltiplos como quilo, mega, giga, penta... byte! Entretanto, aqui cabe uma atenção especial. O termo "quilo" é geralmente denotado para representar mil ou 10³. No binário, por sua vez, "quilo" significa 210, o que resulta em 1024 em decimal. Esta relação continua em toda a escala dos múltiplos de bytes. Com tudo isso em mente, aqui estão os vários prefixos em uso hoje, e a que eles se referem em números reais. Cada múltiplo é mostrado primeiro como seu valor decimal e depois como seu valor binário: • Kilo (kB) = 1.000 bytes = 10³ decimal • Kibi (KiB) = 1.024 bytes = 210 binário • Mega (MB) = 1.000.000 bytes = 106 decimal • Mebi (MiB) = 1.048.576 bytes= 220 binário • Giga (GB) = 1.000.000.000 bytes = 109 decimal • Gibi (GiB) = 1.073.741.824 bytes = 230 binário • Tera (TB) = 1.000.000.000.000 bytes = 1012 decimal • Tebi (TiB) = 1.099.511.627.776 bytes = 240 binário Qual das alternativas apresenta dois componentes da arquitetura de Von Neumann? Resposta: unidade de memória e unidade lógica aritmética. Desenvolvimento de algoritmos Existem muitas definições para o termo algoritmo. As autoras do livro Algoritmos e programação com exemplos em Pascal e C (2014), Nina Edelweiss e Maria Aparecida Livi, indicam que um algoritmo corresponde a uma descrição de um padrão de comportamento expresso em termos de um conjunto finito de ações. Edelweiss e Livi apontam que um algoritmo deve: • Possuir um estado inicial; • Consistir em uma sequência lógica finita de ações; • Produzir dados de saída corretos; • Possuir um estado final. Thomas Cormen et al., em sua obra Algoritmos: teoria e prática (2012), defende que um algoritmo deve ser um procedimento computacional bem definido, que toma um conjunto de valores de entrada e produz um conjunto de valores como saída. Note que tanto Edelweiss e Livi quanto Cormen elencam propriedades de um algoritmo caracterizando, principalmente, que ele deve iniciar (recebendo dados de entrada) e ser concluído (apresentando dados de saída). Podemos definir algoritmo como um procedimento ou fórmula para resolver um problema com base na realização de uma sequência de ações especificadas. Um programa de computador pode ser visto como um algoritmo elaborado. Atente para a palavra utilizada na frase anterior "pode", pois, afinal, um programa é um algoritmo, mas um algoritmo não é um programa. Em matemática e ciência da computação, um algoritmo geralmente significa um pequeno procedimento que resolve um problema recorrente. Porém, um algoritmo não se limita apenas a um programa de computador, ele pode se apresentar de outras maneiras: algoritmo que leve você de casa até a faculdade; algoritmo para fazer um bolo; algoritmo de como dirigir; algoritmo de como resolver um cálculo matemático, entre outros exemplos. SINTAXE DE UM ALGORITMO Como vimos, o algoritmo é uma sequência de ações para resolver um problema. Logo, para que todas as pessoas envolvidas em um projeto possam entender o seu algoritmo,é necessário estabelecer uma convenção ou conjunto de regras que regulem a escrita deste algoritmo. A este conjunto denominamos regras de sintaxe. Quando falamos em regras na computação, estamos por indicar quais tipos de comandos (estruturas de programação) e expressões podem ser utilizados. Os tipos de comandos ou estruturas são: Estrutura sequencial Trata-se da estrutura de controle padrão. As instruções são executadas linha por linha, na ordem em que aparecem; Estrutura condicional É usada para testar uma condição. Uma sequência de instruções é executada dependendo da condição verdadeira ou falsa. Isso significa que o programa escolhe entre dois ou mais caminhos alternativos. Esta condição se refere a qualquer expressão ou valor que retorne um valor booleano, significando verdadeiro ou falso; Estrutura de repetição (ou iteração) Executa repetidamente uma série de instruções em loop, desde que a condição de parada seja verdadeira. A condição de parada pode ser predefinida ou em aberto. Um loop pode ser controlado por evento ou controlado por contador. Um loop controlado por evento executa uma sequência de instruções até que ocorra um evento, enquanto um controlado por contador executa as instruções um número predeterminado de vezes. Nos três tipos de estruturas existem expressões envolvendo a utilização de dados. Não é usual trabalhar diretamente com os valores dos dados; deste modo, são utilizadas variáveis que os armazenam para que sejam realizadas as operações. Uma variável corresponde a um lugar físico na memória do computador, onde ficarão os bits referente aos dados. Acrescentam-se ainda os valores constantes que, diferentemente das variáveis, não podem ser mudados. Por exemplo, o valor de pi na matemática é 3,1415...; na física e na geografia, ele tem o mesmo valor, logo, é uma constante. O saldo bancário é um valor que será modificado, podendo ser de mil reais, dois mil, dois reais ou zero. Chamamos este tipo de valor variável. // Exemplo de sintaxe de um algoritmo Problema: precisamos mostrar na tela do computador a área do círculo com base no dado de entrada (raio) que será informado pelo usuário, sabendo que sua fórmula é área = pi · raio². Resposta: um possível algoritmo que resolve este problema é: inicio_do_algoritmo Primeiro passo: peça ao usuário para digitar o raio do círculo; Segundo passo: calcule a área usando a fórmula pi · raio²; Terceiro passo: exiba o valor na tela. fim_do_algoritmo Note o estado inicial, a solução do problema por meio de uma sequência finita de ações e o estado final, tudo conforme as definições vistas no início deste tópico. // Fluxogramas Além da escrita de uma sequência de ações em português, como foi feito anteriormente, também podemos utilizar fluxogramas, que possuem grande apelo visual. Todo fluxograma possui uma sintaxe e uma semântica muito bem definidas, apresentando símbolos específicos para cada comando, tipos de expressões padronizados e sub-rotinas predefinidas. Enquanto a sintaxe define os símbolos, a semântica define como interpretá-los. A Figura 3 apresenta os principais tipos de componentes do fluxograma. Figura 3. Símbolos de um fluxograma. Utilizando estes elementos, podemos representar o algoritmo do cálculo da área do círculo por meio de um fluxograma. Observe o Diagrama 1. Diagrama 1. Fluxograma para o cálculo da área do círculo. Veja pelo fluxograma que temos o início do algoritmo, a sequência finita de ações e o fim, todos os elementos bem definidos. SEMÂNTICA DE UM ALGORITMO Tendo as regras de escrita (sintática) definidas, é necessário determinar um conjunto de regras para a interpretação do algoritmo, às quais chamaremos regras semânticas. Os símbolos e comandos, por si só, não possuem um significado, por isso precisam estar bem definidos. Vamos olhar o Diagrama 1. O símbolo do retângulo representa o processamento da instrução “Área ← pi · raio²”. É um tipo de símbolo que será executado de forma imperativa, uma vez que não existe condição imposta a ele. A instrução interna ao retângulo é condizente com a ação dele, logo, o símbolo está semanticamente correto. Note, então, que a semântica sempre deve acompanhar a sintaxe. Por exemplo, o símbolo de retângulo não poderia representar o início ou o fim de um fluxograma, uma vez que ele não possui esta funcionalidade. // Exemplo não computacional de um algoritmo Um exemplo de algoritmo que está fora do contexto computacional é o procedimento para se fritar um ovo. Vamos lá. Início • Coloque um pouco do óleo na frigideira; • Acenda o fogo; • Coloque a frigideira sobre o fogo; • Espere o óleo esquentar; • Quebre o ovo; • Despeje o ovo no óleo quente; • Coloque um pouco de sal no ovo; • Retire o ovo quando estiver pronto. Fim // Exemplo computacional de um algoritmo Um exemplo concreto do uso de algoritmo pode ser feito quando, dados dois valores, temos que encontrar qual deles é o maior e apresentá-lo na tela. Note que existe uma condição simples: se um número X for maior que um número Y, então mostraremos o número X na tela; caso contrário (senão), apresentaremos o número Y na tela. Vamos então ao algoritmo. Início • Pedir para o usuário fornecer valores inteiros para X e Y; • SE X > Y ENTÃO • Mostrar o valor de X na tela; • SENÃO • Mostrar o valor de Y na tela; Fim Podemos simular a execução deste algoritmo utilizando o conceito de teste de mesa. Em um teste de mesa, simulamos algumas possíveis entradas do usuário, com o objetivo de entender a execução do algoritmo ou código e verificar se o algoritmo realmente chega ao objetivo para o qual foi projetado. Neste teste, colocaremos o comando, bem como as variáveis, conforme o Quadro 1. Quadro 1. Teste de mesa do algoritmo para encontrar maior valor. 5. No teste condicional, 6 é maior que 5, logo, ele foi apresentado. Mas veja agora o teste do Quadro 2. Nele, o usuário informa os valores 50 e 51, respectivamente, para X e Y. Quadro 2. Teste de mesa do algoritmo para encontrar maior valor. Para este segundo teste, X é igual a 50 e Y igual a 51. No teste condicional SE X > Y, a relação é falsa, logo, não é mostrado o valor de X na tela, mas, sim, o valor de Y. Note a instrução SENÃO indicando um segundo caminho na execução do algoritmo. O Diagrama 2 possibilita visualizar os dois caminhos possíveis que podem ser obtidos por esse algoritmo. Note que a saída à direita é para quando X é maior que Y, e a saída à esquerda é para quando Y é maior que X. Diagrama 2. Fluxograma do algoritmo para encontrar o maior número entre X e Y. Veja que com o fluxograma fica mais prático compreender o comportamento de execução do algoritmo. Nele, temos o início, as instruções finitas e o fim. Sendo verdadeira ou falsa a comparação, o fluxograma sempre terminará no último símbolo chamado fim. TIPOS DE DADOS E CONVENÇÕES Até agora nós apenas criamos os algoritmos e os mostramos em “execução”. Porém, olhe o que fizemos e perceba que nem no algoritmo nem no fluxograma há indicação explícita do tipo de valor que está em operação. Por exemplo, os números 50 e 51, bem como o 6 e o 5, podem ser utilizados como números inteiros ou números reais. Logo, nos exemplos que vimos anteriormente, não tem como defini-los. Por outro lado, os números 50,19 e 51,8 são, certamente, números reais, pois existe uma vírgula separando as casas decimais. Além disso, existem valores como caracteres (uma única letra ou número), strings ou cadeias de caracteres (possui dois ou mais caracteres) e valores lógicos. Esses são os tipos primitivos de dados e os veremos agora. Números Em um algoritmo, podemos trabalhar tanto com números inteiros quanto com números reais. Estes últimos são escritos com separadorde casas decimais. Por exemplo, ao pesar um determinado material, obtivemos o valor 40, que pode ser inteiro ou real. Se nosso objetivo era apenas pesar e saber o valor, sem se preocupar com a precisão, então podemos declarar uma variável como inteira, logo, o 40 apresentado é inteiro. Porém, se desejamos obter precisão na aferição, a variável precisa ser declarada como número real, deste modo, podemos obter um peso como 40,0002. Note a presença das casas decimais. Caracteres e cadeias de caracteres Entende-se como caractere a presença de uma única letra, número ou símbolo. Todo caractere em linguagem de programação é limitado com aspas simples. Deste modo, o caractere A será representado como ‘A’. Isso ocorre para evitar confusão entre o valor do caractere e o nome de uma variável, bem como para diferenciar um número cinco (que é inteiro) de um número ‘5’ (entre aspas simples, que é um caractere). Símbolos como ‘@’, ‘\’, ‘/’, espaço em branco e outros também são representados como caracteres. Quando existem dois ou mais caracteres juntos, chamamos de cadeia de caracteres ou strings. Por exemplo, a palavra “programação” é uma string ou cadeia de caracteres. Note que, neste caso, usamos aspas duplas para delimitar uma string. Outro exemplo: “programação de computadores”, veja que aqui, além das letras, também há espaços em branco que fazem parte da string. Valores lógicos George Boole elaborou a lógica booleana e, em sua homenagem, foi criado o tipo chamado booleano ou tipo lógico. Este tipo de dados, diferentemente dos anteriores, apenas possui dois valores: verdadeiro ou falso, sendo convencionado tratá-los na grafia inglesa: true ou false. Estes valores são estudados em expressões lógicas e estruturas condicionais. // Nomes de variáveis Vimos então os tipos primitivos de dados: inteiro, real e caractere. Agora, veremos que existem convenções para declarar o nome das variáveis, e é importante que sejam seguidas para que não haja erros de execução ou interpretação de leitura do código. • O nome de uma variável deve ter, no máximo, 63 caracteres; • O nome deve ser iniciado obrigatoriamente por uma letra ou por ‘_’; • O nome só pode possuir número se começar com letra; • O nome da variável somente aceita: letras, números e o caractere ‘_’; • Letras gregas ou outras fora do alfabeto ocidental não são aceitas; • Algumas linguagens de programação são case sensitive, ou seja, A (maiúsculo) é diferente de a (minúsculo). Exemplos de NOMES válidos de VARIÁVEIS • numero; • vetor; • num1; • coord_X; • _resultado; • ValorTotal; • valor_parcial. Exemplos de NOMES inválidos de VARIÁVEIS • n umero; • @vetor; • N 1; • num-fim; • x&a; • R$. Note que o espaço em branco é um erro, pois pode parecer que se tratam de duas variáveis diferentes. Os caracteres especiais não devem ser utilizados em variáveis. O caracter ‘-‘ não pode ser utilizado, uma vez que ele, na programação, tem o papel reservado para realizar operações de subtração. OPERAÇÕES ARITMÉTICAS Na montagem do algoritmo ou de um código de programação, podemos considerar as quatro operações aritméticas, que são: adição, subtração, multiplicação e divisão. Dependendo do tipo de variável e dos operadores, o resultado da operação pode ser diferente, e isso ocorre em três casos: divisão real, divisão inteira e obtenção do resto da divisão. Todas estas operações são binárias, pois consideram a relação entre dois operandos. Outro tipo de operação existente é a troca de sinal, que, diferente das anteriores, é uma operação unária, pois realiza a troca de sinal de apenas um operando. Apesar de caracterizarmos apenas a relação entre números inteiros e números reais, também podemos utilizar a operação de adição em cadeias de caracteres. Por exemplo, considere uma variável A, que contém a cadeia “Programação”, e uma variável B, que possui a cadeia de caracteres “Computadores”. Ao fazermos C ← A + B, o resultado em C será “ProgramaçãoComputadores”. Denominamos este tipo de adição com cadeia de caracteres concatenação. Veremos agora um exemplo de pseudocódigo de algoritmo que, ao receber dois números inteiros, realizará a divisão (operação div) e também obterá o resto da divisão utilizando a operação mod. Algoritmo: Início • Pedir para o usuário fornecer valores inteiros para A e B; • Result ← A div B; • Resto ← A mod B; • Mostrar na tela result e resto. Fim Diagrama 3. Fluxograma de operações aritméticas. Agora faremos o teste de mesa simulando a interação do usuário com o algoritmo. A variável A receberá o valor 8, enquanto a variável B receberá o valor 5. Faremos a operação de divisão de inteiros e também obteremos o resto da divisão armazenando, respectivamente, nas variáveis result e resto, seguindo a ordem de execução do algoritmo e do Diagrama 3. Vejamos então estas operações no teste de mesa do Quadro 3. Quadro 3. Teste de mesa do algoritmo apresentado. Quando dividimos o inteiro 8 pelo inteiro 5, o resultado da divisão (Result ← A div B) será 1, pois a parte inteira de 8 dividida por 5 é 1. O valor do resto dessa divisão é 3, que foi obtido na operação Resto ← A mod B. De acordo com seus conhecimentos, relacione as colunas a seguir: Sequencial => Instruções executadas linha após linha Condicional => Expressão que retorne valor booleano Repetição => Loop controlado por evento Linguagens de programação Uma linguagem de programação é uma notação projetada para conectar instruções a uma máquina ou um computador. As linguagens de programação são usadas, principalmente, para controlar o desempenho de uma máquina ou para expressar algoritmos. Existem milhares de linguagens de programação implementadas, algumas para objetivos gerais e outras para fins específicos. Muitas destas linguagens precisam ser declaradas de forma imperativa, enquanto outras utilizam a forma declarativa. O programa pode ser dividido de duas formas: como sintaxe e como semântica. Pensa-se que o primeiro computador programável a ser projetado (embora nunca tenha sido realmente concluído) seja o Analytical Engine, concebido em 1835 por Charles Babbage, e destinado a ser usado para resolver problemas computacionais gerais. Nesse esforço, Babbage foi assistido por Lady Ada Lovelace, que hoje é amplamente considerada a primeira programadora de computador. Ela introduziu muitos conceitos de programação em uso até hoje, incluindo o uso de loops para lidar com tarefas repetitivas e o uso de sub-rotinas que podem ser chamadas de qualquer lugar dentro de um programa. O primeiro computador eletromecânico programável foi construído na Alemanha, em 1941, por Konrad Zuse, embora seu significado pareça ter sido ignorado pelos militares alemães. Durante a década de 1940, vários outros cientistas da computação começaram a desenvolver a ideia de computadores com programas armazenados nos quais as instruções e os dados podiam ser gravados, na memória do computador. Um artigo de 1936 do matemático Alan Turing havia descrito tal máquina. Turing publicou especificações de projeto detalhadas para um programa de computador em 1946, mas um artigo publicado por John Von Neumann, em 1945, foi mais amplamente divulgado e, consequentemente, recebeu muito mais atenção. Sistemas de computador existentes, como o computador Colossus, usado pelos britânicos durante a guerra para decifrar os códigos militares alemães, e o computador ENIAC, usado após a guerra pelos americanos para desenvolver a bomba de hidrogênio, foram programados ajustando interruptores e controlando dados. O Diagrama 4 demonstra a organização dos diferentes paradigmas de programação. Daremos ênfase em cada um destes paradigmas, e citaremos conceitualmente as principais linguagens relacionadas a eles. Diagrama 4. Paradigmasde linguagem de programação. Vamos estudar agora sobre os diferentes paradigmas de linguagens de programação e as diferenças entre eles. PARADIGMAS Cada linguagem tende a suportar um paradigma (ou estilo) particular de programação. Embora vários fatores possam afetar a escolha da linguagem de programação para uma tarefa específica, incluindo preferência pessoal, política corporativa ou simplesmente a disponibilidade de conhecimento e experiência interna suficientes, a linguagem selecionada deve ser a mais adequada para a tarefa em questão. Qualquer que seja a linguagem escolhida, os seguintes recursos são comuns à maioria: Entrada Obtenha dados de um dispositivo de entrada, como uma unidade de disco ou o teclado; Saída Envie dados para um dispositivo de saída, como uma unidade de disco, unidade de exibição visual, impressora ou adaptador de rede; Aritmética e lógica Execute operações aritméticas, como adição e multiplicação, e operações lógicas, como comparar o valor de duas variáveis; Execução condicional Execute um conjunto diferente de instruções do programa, dependendo de uma condição especificada ser verdadeira ou falsa; Repetição Execute um conjunto de instruções do programa repetidamente, até que alguma condição de saída seja avaliada como verdadeira (um loop condicional) ou para um número especificado de iterações (um loop de contagem). Serão apresentados a seguir os principais paradigmas de programação. Entretanto, vale reforçar que, atualmente, as linguagens de programação são multiparadigmas, ou seja, uma mesma linguagem pode possuir dois ou mais paradigmas. // Paradigma imperativo A palavra "imperativo" vem do latim impero, que significa "eu ordeno". É a mesma palavra que originou "imperador", e esta relação é bastante adequada. Neste paradigma, o desenvolvedor é o imperador. Você dá ao computador pequenas ordens e ele as executa uma de cada vez e as informa. O paradigma consiste em várias instruções e, após a execução de todas elas, o resultado é armazenado. Trata-se de escrever uma lista de instruções para informar ao computador o que fazer passo a passo. Os exemplos de algoritmos que vimos até aqui são imperativos. Em um paradigma de programação imperativo, a ordem das etapas é crucial, porque uma determinada etapa terá consequências diferentes, dependendo dos valores das variáveis no momento em que a etapa é executada. O fluxo de controle na programação imperativa é explícito: os comandos mostram como a computação ocorre, passo a passo. Cada etapa afeta o estado global da computação. // Paradigma procedural A programação procedural é um paradigma de programação estruturado com base no conceito de chamada de procedimento. Os procedimentos em questão podem ser sub-rotinas, métodos ou funções; cada um deles consiste em uma coleção de instruções do programa, que são realizadas sequencialmente para executar uma tarefa específica. Um procedimento pode ser chamado a partir de qualquer ponto de um programa e pode chamar outros procedimentos. Um benefício evidente das linguagens procedurais é que elas permitem que o mesmo código seja reutilizado repetidamente, em vez de forçar o programador a escrever o mesmo código várias vezes. Eles também evitam a necessidade de usar as instruções GOTO ou JUMP, encontradas em linguagens não estruturadas e que em programas grandes frequentemente resultam no chamado "código espaguete". Linguagens procedurais também são adequadas para modularização. Os programas modulares consistem em vários módulos de código distintos, cada um lidando com um aspecto específico de um aplicativo. Por exemplo, o programador pode decidir coletar todo o código processual para lidar com a funcionalidade de processamento de dados em um módulo e o código para gerar a interface gráfica do usuário do aplicativo em outro. Essa abordagem ajuda a reduzir a complexidade geral de um aplicativo grande, organizando o código do aplicativo em unidades funcionais relacionadas. As principais linguagens de programação deste paradigma são: • C; • C ++; • Java; • Pascal. // Paradigma orientado a objetos A programação orientada a objetos (POO) é um paradigma que usa objetos para modelar entidades de dados. Assim, amplia a ideia de modularização, mas enfatiza os dados e não as funções desempenhadas pelo programa. Uma entidade do mundo real, como uma conta bancária ou um cliente, pode ser modelada como um objeto. Os traços que descrevem a entidade do mundo real, como número da conta ou ID do cliente, são incorporados no objeto como variáveis ou atributos. O objeto também possui vários métodos (funções ou procedimentos) que podem ser chamados para recuperar suas informações ou modificar o estado dele. Os objetos interagem com os usuários do aplicativo e entre si, enviando e recebendo mensagens. As mensagens que um objeto responderá são definidas por sua interface. Os aplicativos são produzidos ao criar objetos para representar as entidades de dados que serão manipuladas pelo aplicativo. Os dados do objeto e os detalhes precisos de como seus métodos são implementados são ocultos para entidades externas. De um modo geral, os atributos de um objeto são declarados como privados e só podem ser acessados ou modificados pelos métodos do próprio objeto. Os métodos em si geralmente são declarados públicos, mas as maneiras pelas quais eles podem ser chamados são estritamente definidas pela sua interface. A capacidade de ocultar os dados e a implementação de código de um objeto atrás de sua interface são chamadas encapsulamento. Objetos como clientes e contas bancárias tendem a existir em grande número em situações do mundo real. Deste modo, pode-se supor que um aplicativo que modele um sistema bancário ou departamento de atendimento ao cliente precisará fornecer muitos objetos do mesmo tipo. Nas linguagens de programação orientadas a objetos, cada um é derivado de um objeto de modelo chamado classe. A classe define os atributos, métodos e interface para cada objeto criado a partir dela. Um objeto criado a partir de uma classe específica é, portanto, considerado uma instância única dessa classe. A ideia de classes pode ser estendida para permitir que variações na classe original sejam definidas como subclasses. Por exemplo, poderíamos ter uma classe principal chamada ContaBancaria, da qual poderíamos derivar duas subclasses denominadas ContaCorrente e ContaPoupanca. As duas subclasses herdariam os atributos, métodos e interface de ContaBancaria (a classe pai), mas cada uma poderia ser modificada para refletir sua função mais especializada. A capacidade de uma subclasse de herdar as características de sua classe pai é chamada herança. As linguagens de programação orientadas a objetos existem desde a década de 1960. Pensa-se que o Simula seja a primeira linguagem de programação a exibir características orientadas a objetos, enquanto a primeira verdadeiramente orientada a objetos é considerada por muitos a Smalltalk. Somente nos anos 90, porém, a programação orientada a objetos emergiu como o paradigma predominante, provavelmente devido ao aumento da popularidade da interface gráfica do usuário – para a qual uma abordagem orientada a objetos é ideal. Embora a maioria das linguagens de programação tenha adotado características orientadas a objetos até certo ponto, as linguagens atualmente em destaque incluem: • Smalltalk (primeira linguagem orientada a objeto); • Python; • Ruby; • Java; • C++; • Visual Basic.Net. // Paradigma processamento paralelo Neste paradigma, o processamento das instruções do programa é dividido entre vários processadores. Um sistema de processamento paralelo permite que muitos processadores executem um programa em menos tempo. A abordagem de processamento paralelo geralmenteé mais bem usada quando: • Você tem um sistema que possui mais de uma CPU ou processadores multinúcleos (muito comum nos computadores atuais); • Você precisa resolver alguns problemas computacionais que levam horas ou dias para serem resolvidos, mesmo com o benefício de um microprocessador mais poderoso; • Você trabalha com dados do mundo real que precisam de simulação e modelagem mais dinâmicas. Linguagens que suportam a abordagem de processamento paralelo: • NESL (um dos mais antigos); • C; • C ++. PARADIGMA DECLARATIVO O paradigma declarativo é um estilo de construção de programas que expressa a lógica de uma computação sem falar sobre seu fluxo de controle. A programação declarativa é um paradigma em que o programador define o que precisa ser realizado sem definir como ele deve ser implementado. Em outras palavras, a abordagem enfoca o que precisa ser alcançado em vez de instruir como alcançar. Portanto, as principais diferenças entre o paradigma imperativo e o paradigma declarativo é que o primeiro indica como fazer, e o segundo indica o que fazer. // Paradigma de lógica O paradigma da programação lógica adota uma abordagem declarativa para a solução de problemas. É baseado na lógica formal. Ele não é composto de instruções, mas, sim, de fatos e cláusulas. Usa tudo o que sabe e tenta criar o mundo em que todos esses fatos e cláusulas são verdadeiros. Por exemplo: Sócrates é um homem, todos os homens são mortais e, portanto, Sócrates é mortal. A seguir, é apresentado um programa Prolog simples, que explica essa instância: homem(Socrates). mortal(X) :- homem(X). A primeira linha pode ser lida como: "Sócrates é um homem". É uma cláusula básica, que representa um fato simples. A segunda linha pode ser lida como: "X é mortal se X é um homem", em outras palavras, todos os homens são mortais. Esta é uma cláusula, ou regra, para determinar quando a sua entrada X é "mortal". O símbolo : - é pronunciado como “se”. Podemos testar o programa fazendo a pergunta: ?- mortal(Socrates). Isto é, “Sócrates é mortal?”, sendo que a interrogação é o prompt do computador para fazer uma pergunta. O Prolog responderá "yes''. Exemplos de linguagens deste paradigma: • Prolog; • Absys; • ALF (linguagem de programação funcional de lógica algébrica); • Alice; • Ciao. // Paradigma funcional O paradigma de programação funcional está no centro das atenções há um tempo por conta do JavaScript, que ganhou mais popularidade recentemente. O paradigma de programação funcional tem suas raízes na matemática e é independente de linguagem. O princípio-chave desse paradigma é a execução de uma série de funções matemáticas. Você compõe seu programa de funções curtas. Todo o código está dentro de uma função. Todas as variáveis têm escopo definido para a função. No paradigma de programação funcional, as funções não modificam nenhum valor fora do escopo dessa função, e as próprias funções não são afetadas por nenhum valor fora do escopo. Para ilustrar, vamos identificar se o número fornecido é primo ou não com o paradigma de programação funcional, utilizando JavaScript: function verificaPrimo(numero){ for(let i=2; i<=Math.floor(Math.sqrt(numero)); i++){ if(numero % i == 0 ){ return false; } } return true; } verificaPrimo(15); //retorna “false” No exemplo anterior, usamos funções matemáticas Math.floor() e Math.sqrt() para resolver nosso problema com eficiência. Podemos resolver esse problema sem usar funções matemáticas nativas do JavaScript, mas, para executar o código com eficiência, é recomendável usar funções incorporadas. A variável numero está com escopo definido para a função verificaPrimo() e não será afetada por nenhum valor fora dele. A função sempre produz a mesma saída quando recebe a mesma entrada. Exemplos de linguagens que suportam este paradigma: • Haskell; • OCaml; • Scala; • Clojure; • Racket; • JavaScript. // Paradigma database (paradigma de processamento de banco de dados) Este paradigma de programação é baseado em dados e seu movimento. As instruções do programa são definidas pelos dados em vez de codificarem uma série de etapas. Para processar os dados e consultá-los, os bancos de dados usam tabelas. Os dados podem ser facilmente acessados, gerenciados, modificados, atualizados, controlados e organizados. Uma boa abordagem de processamento de banco de dados é crucial para qualquer empresa ou organização, porque ele armazena todos os detalhes pertinentes sobre a empresa, como registros de funcionários, registros de transações e detalhes de salário. A maioria dos bancos de dados usa o SQL (Structured Query Language) para gravar e consultar dados. Aqui está um exemplo na abordagem de processamento de banco de dados (SQL): CREATE DATABASE detalhesPessoais; CREATE TABLE Pessoa ( PessoaID int, UltimoNome varchar(255), PrimeiroNome varchar(255), Endereco varchar(255), Cidade varchar(255) ); A coluna PessoaID é do tipo int e conterá um número inteiro. As colunas UltimoNome, PrimeiroNome, Endereco e Cidade são do tipo varchar e conterão valores do estilo cadeia de caracteres (string), e o comprimento máximo para esses campos é de 255 caracteres, conforme definido entre parênteses. PARADIGMA DE PROGRAMAÇÃO ORIENTADA A EVENTOS A programação orientada a eventos é um paradigma no qual o fluxo de execução do programa é determinado por eventos – por exemplo, uma ação do usuário, como um clique do mouse, pressionamento de tecla, uma mensagem do sistema operacional ou de outro programa. Um programa orientado a eventos é projetado para: • Detectar eventos à medida que eles ocorrem; • Lidar com eventos usando um procedimento de manipulação apropriado. Como nos outros paradigmas apresentados, não existe apenas uma linguagem de programação para este, embora algumas linguagens (Visual Basic, por exemplo) sejam projetadas especificamente para facilitar essa programação e forneçam um ambiente de desenvolvimento integrado (IDE - Integrated Development Environment) que automatiza parcialmente a produção de código, além de fornecer uma seleção abrangente de objetos e controles internos, cada um podendo responder a uma variedade de eventos. De modo geral, todas as linguagens visuais e orientadas a objetos suportam programação orientada a eventos. Visual Basic, Visual C++ e Java são exemplos dessas linguagens. Um IDE de programação visual, como o VB.Net, fornece grande parte do código para detectar eventos automaticamente quando um novo aplicativo é criado. O programador pode, portanto, concentrar-se em questões como o design da interface, que envolve adicionar controles, como botões de comando, caixas de texto e labels aos formulários (um formulário representa o espaço de trabalho ou a janela de um programa). Quando a interface do usuário estiver completa, o programador poderá adicionar um código de manipulação de eventos a cada controle, conforme necessário. Muitos ambientes de programação visual fornecem modelos de código para manipuladores de eventos, portanto, o programador só precisa prover o código que define a ação que o programa deve executar quando o evento ocorrer. Cada manipulador de eventos geralmente é vinculado a um objeto ou controle específico em um formulário. Quaisquer sub-rotinas, métodos ou procedimentos de função adicionais necessários geralmente são colocados em um módulo de código separado e podem ser considerados outras partes do programa, conforme e quando necessário. LINGUAGENS DE BAIXO E DE ALTO NÍVEL A principal diferença entre elas é que a linguagem de alto nível é facilmente interpretada pelos programadores, mas não pelas máquinas, enquanto a linguagem de baixo nível pode ser facilmente entendida pelas máquinas, mas não pelos humanos.A linguagem de baixo nível é compreendida pela linguagem de máquina e linguagem assembly. Linguagem de baixo nível A linguagem de baixo nível é considerada baixa porque vai para o nível da máquina e pode determinar como os elementos de hardware do computador realmente interagem. Essas linguagens de baixo nível precisam de um amplo conhecimento dos componentes de hardware e de suas configurações. São linguagens de baixo nível: • Linguagem de máquina: é considerada a linguagem natural do computador, que pode ser reconhecida diretamente pelas máquinas eletrônicas. É uma linguagem não portátil e dependente da máquina, que consiste em apenas dois números binários, 0 e 1. Cada instrução em um computador existe na forma de código binário. No entanto, é bastante difícil fornecer instruções a um computador em uma linguagem binária, ou seja, escrever programas em linguagem no nível da máquina. As velocidades de gravação, teste e depuração na linguagem de máquina são lentas, e erros incautos são muito comuns. • Linguagem assembly: nessa linguagem, os programadores usam comandos que se assemelham um pouco ao inglês comum, que é compreensível até certo ponto e interpretado pelos programadores. Os programas são construídos usando símbolos alfanuméricos (também conhecidos como mnemônicos) em vez de 0s e 1s. Inclui ADD, SUB, MUL, DIV, RLC e RAL como símbolos ou mnemônicos. Linguagens como C, Java, Visual Basic e outras já vistas anteriormente são traduzidas para linguagem de máquina. O assembler (montador) é usado para executar essas operações a fim de traduzir a linguagem não máquina para a linguagem da máquina. Cada processador é ativado com sua própria linguagem de montagem, como os processadores 8085, 8086, 80186, que possuem suas próprias linguagens de montagem. Linguagem de alto nível Linguagens de alto nível são construídas por uma combinação de símbolos matemáticos, caracteres e símbolos da linguagem natural, sendo modeladas por cenários do mundo real. De uma maneira geral, as linguagens de programação modernas são conhecidas como de alto nível. Estas são implementadas, principalmente, para o desenvolvimento rápido e fácil de um programa. Não é necessário memorizar a arquitetura e os registros de uma CPU para o desenvolvimento de um programa. Os compiladores são usados para traduzir o programa de linguagem de alto nível para a linguagem de máquina. Existem várias linguagens de alto nível, como COBOL, FORTRAN, BASIC, C e C ++, Java, entre outras. // Principais diferenças entre linguagem de baixo nível e linguagem de alto nível • A linguagem de alto nível é amigável para programadores. Por outro lado, a linguagem de baixo nível é amigável à máquina, o que significa que é interpretada facilmente por máquinas; • Linguagens de baixo nível levam um tempo maior para serem executadas se compararmos às linguagens de alto nível; • Linguagens de alto nível são convertidas em linguagem específica da máquina com a ajuda de um compilador. Por outro lado, com linguagens de baixo nível, apenas um assembler é necessário para a linguagem assembly; • Quando se trata de consumo de memória, as linguagens de baixo nível são altamente eficientes, por outro lado, linguagens de alto nível consomem mais memória; • Uma linguagem de alto nível é facilmente compreensível para programadores, enquanto a linguagem de baixo nível não pode ser interpretada facilmente, pois contém um conjunto de longas séries de zeros e uns; • As linguagens de baixo nível não podem ser executadas em máquinas diferentes, pois não são portáteis e são fortemente dependentes da máquina. Por outro lado, os programas escritos em linguagens de alto nível são portáteis e independentes de máquinas; • A manutenção em programas escritos em linguagem de alto nível é mais fácil se comparada à manutenção em linguagens de baixo nível. Por fim, as linguagens de baixo nível são usadas principalmente para construir aplicações menos operacionais, sendo necessárias funções simples e específicas, como máquinas CNC (Computer Numeric Control – controle numérico computadorizado), dispositivos eletrônicos, entre outros. Por outro lado, linguagens de alto nível são usadas para criar aplicações abrangentes, nas quais uma longa sequência de funções é realizada, como softwares usados em hospitais, indústrias, fábricas etc. Em relação aos paradigmas de programação, é correto dizer (marque uma ou mais alternativas, se necessário): • No paradigma imperativo, você dá ao computador pequenas ordens que ele executa uma de cada vez, além de informá-las. • No paradigma funcional, o princípio chave é a execução de uma série de funções matemáticas. • O paradigma declarativo expressa a lógica de uma computação sem falar sobre seu fluxo de controle. Agora é a hora de sintetizar tudo o que aprendemos nessa unidade. Vamos lá?! SINTETIZANDO Durante a leitura desta unidade, você pôde compreender a arquitetura organizacional de um computador. Viu que a arquitetura de Von Neumann é dividida em três partes: entrada, processamento e saída, sendo que esse modelo está presente em todos os sistemas computacionais, sejam eles desktops, smartphones ou grandes computadores de processamento pesado. Pôde compreender que os algoritmos são uma sequência finita de ações, com início e fim bem evidentes, e que a linguagem de programação é como nós passamos ao computador esses algoritmos, dizendo o que ele tem que fazer e quando tem que fazer. Vimos que existem linguagens de baixo nível e de alto nível. Enquanto as linguagens de baixo nível são usadas para construir aplicações menos operacionais, como máquinas CNC e dispositivos eletrônicos, as linguagens de alto nível são usadas para criar aplicações de operações abrangentes, como softwares de uso geral, aplicativos para celular e sites. Por fim, conhecemos os principais paradigmas de programação. Vimos que a maioria das linguagens de programação implementa dois ou mais paradigmas. Em casos em que uma linguagem implementa apenas um paradigma, dizemos que ela é pura. É incrivelmente raro ter uma linguagem pura em orientação a objetos ou uma linguagem pura funcional. As linguagens de programação são, em sua maioria, multiparadigmáticas.
Compartilhar