Baixe o app para aproveitar ainda mais
Prévia do material em texto
AULA 9 NÚMEROS COM PONTO FLUTUANTE Dadas as dificuldades inerentes da representação de números reais nos computadores, as linguagens de programação de alto nível procuram superá-las abstraindo essa representação através do uso de números com ponto flutuante. Na linguagem C, números com ponto flutu- ante podem ser manipulados como constantes ou variáveis do tipo ponto flutuante. O armaze- namento destes números em memória se dá de forma distinta do armazenamento de números inteiros e necessita de mais espaço, como poderíamos supor. Nesta aula veremos como manipular números de ponto flutuante, formalizando as defini- ções de constantes e variáveis envolvidas, além de aprender as regras de uso desses elementos em expressões aritméticas. Esta aula é baseada nos livros [6, 10]. 9.1 Constantes e variáveis do tipo ponto flutuante Números inteiros não são suficientes ou adequados para solucionar todos os problemas algorítmicos. Muitas vezes são necessárias variáveis que possam armazenar números com dígitos após a vírgula, números muito grandes ou números muito pequenos. A vírgula, especi- almente em países de língua inglesa, é substituída pelo ponto decimal. A linguagem C permite que variáveis sejam declaradas de forma a poderem armazenar números de ponto flutuante, com os tipos básicos float e double . Uma constante do tipo ponto flutuante se distingue de uma constante do tipo inteiro pelo uso do ponto decimal. Dessa forma, 3.0 é uma constante do tipo ponto flutuante, assim como 1.125 e -765.567 . Podemos omitir os dígitos antes do ponto decimal ou depois do ponto decimal, mas obviamente não ambos. Assim, 3. e -.1115 são constantes do tipo ponto flutuante válidas. Na linguagem C, uma variável do tipo ponto flutuante pode armazenar valores do tipo ponto flutuante e deve ser declarada com a palavra reservada float ou double . Por exem- plo, a declaração float x, y; double arco; realiza a declaração das variáveis x e y como variáveis do tipo ponto flutuante. 90 9 NÚMEROS COM PONTO FLUTUANTE 91 A distinção entre os tipos de ponto flutuante float e double se dá pela quantidade de precisão necessária. Quando a precisão não é crítica, o tipo float é adequado. O tipo double fornece precisão maior. A tabela a seguir mostra as características dos tipos de ponto flutuante quando implemen- tados de acordo com o padrão IEEE1. Em computadores que não seguem o padrão IEEE, esta tabela pode não ser válida. Tipo Menor valor (positivo) Maior valor Precisão float 1.17549× 10−38 3.40282× 1038 6 dígitos double 2.22507× 10−308 1.79769× 10308 15 dígitos O padrão IEEE 754 estabelece dois formatos primários para números de ponto flutuante: o formato de precisão simples, com 32 bits, e o formato de precisão dupla, com 64 bits. Os números de ponto flutuante são armazenados no formato de notação científica, composto por três partes: um sinal, um expoente e uma fração. O número de bits reservado para representar o expoente determina quão grande o número pode ser, enquanto que o número de bits da fração determina sua precisão. Um exemplo de um programa que usa constantes e variáveis do tipo float é apresentado no programa 9.1. Neste programa, uma sequência de cem números do tipo ponto flutuante é informada pelo usuário. Em seguida, a média aritmética desses números é calculada e, por fim, mostrada na saída padrão. Programa 9.1: Calcula a média de 100 números do tipo ponto flutuante. #include <stdio.h> /* Recebe uma sequência de 100 números reais e mostra a média desses números */ int main(void) { int i; float numero, soma, media; soma = 0.0; for (i = 1; i <= 100; i++) { printf("Informe um número: "); scanf("%f", &numero); soma = soma + numero; } media = soma / 100; printf("A média dos 100 números é %f\n", media); return 0; } Observe que a cadeia de caracteres de formatação contém um especificador de conversão para um número de ponto flutuante %f , diferentemente do especificador de conversão para números inteiros ( %d ) que vimos anteriormente. 1 Instituto de Engenheiros Elétricos e Eletrônicos, do inglês Institute of Electrical and Eletronics Engineers (IEEE). FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 92 9.2 Expressões aritméticas Na linguagem C existem regras de conversão implícita de valores do tipo inteiro e do tipo ponto flutuante. A regra principal diz que o resultado da avaliação de uma expressão aritmética será do tipo ponto flutuante caso algum de seus operandos – resultante da avaliação de uma expressão aritmética – seja também do tipo ponto flutuante. Caso contrário, isto é, se todos os operandos são do tipo inteiro, o resultado da expressão aritmética será um valor do tipo inteiro. Vejamos um exemplo no programa 9.2. Programa 9.2: Relação entre valores do tipo inteiro e do tipo ponto flutuante. #include <stdio.h> /* Teste 1 com números inteiros e reais */ int main(void) { int i1, i2; float f1, f2; i1 = 190; f1 = 100.5; i2 = i1 / 100; printf("i2 = %d\n", i2); f2 = i1 / 100; printf("f2 = %f\n", f2); f2 = i1 / 100.0; printf("f2 = %f\n", f2); f2 = f1 / 100; printf("f2 = %f\n", f2); return 0; } O resultado da execução desse programa é apresentado a seguir. i2 = 1 f2 = 1.000000 f2 = 1.900000 f2 = 1.005000 O primeiro valor é um número do tipo inteiro que representa o quociente da divisão de dois números do tipo inteiro 190 e 100 . Já tínhamos trabalhado com expressões aritméticas semelhantes em aulas anteriores. No segundo valor temos de olhar para a expressão aritmé- tica à direita do comando de atribuição. Esta expressão é uma expressão aritmética que só contém operandos do tipo inteiro. Por isso, o resultado é o número do tipo inteiro 1 , que é atribuído à variável f2 . O comando printf mostra o conteúdo da variável f2 como um número do tipo ponto flutuante e assim a saída é f2 = 1.000000 . Em seguida, nas próximas duas impressões, as expressões aritméticas correspondentes contêm operandos do tipo ponto flutuante: a constante do tipo ponto flutuante 100.0 na primeira e a variável do tipo ponto flutuante f1 na segunda. Por isso, as expressões aritméticas têm como resultados números do tipo ponto flutuante e a saída mostra os resultados esperados. FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 93 Suponha, no entanto, que um programa semelhante, o programa 9.3, tenha sido desenvol- vido, compilado e executado. Programa 9.3: Operações e tipos inteiro e de ponto flutuante. #include <stdio.h> /* Teste 2 com números inteiros e reais */ int main(void) { int i1, i2; float f1; i1 = 3; i2 = 2; f1 = i1 / i2; printf("f1 = %f\n", f1); return 0; } O resultado da execução deste programa é: f1 = 1.000000 Mas e se quiséssemos que a divisão i1 / i2 tenha como resultado um valor do tipo ponto flutuante? Neste caso, devemos usar um operador unário chamado operador conversor de tipo, do inglês type cast operator, sobre algum dos operandos da expressão. No caso acima, poderíamos usar qualquer uma das atribuições abaixo: f1 = (float) i1 / (float) i2; f1 = (float) i1 / i2; f1 = i1 / (float) i2; e o resultado e a saída do programa seria então: f1 = 1.500000 O operador (float) é assim chamado de operador conversor do tipo ponto flutuante. Um outro operador unário, que faz o inverso do operador conversor do tipo ponto flutuante, é o operador conversor do tipo inteiro, denotado por (int) . Esse operador conversor do tipo inteiro converte o valor de seu operando, no caso uma expressão aritmética, para um valor do tipo inteiro. Vejamos agora o programa 9.4. FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 94 Programa 9.4: Uso de operadores conversores de tipo. #include <stdio.h> /* Teste 3 com números inteiros e reais */ int main(void) { int i1, i2, i3, i4; float f1, f2; f1 = 10.8; f2 = 1.5; i1 = f1 / f2; printf("i1 = %d\n", i1); i2 = (int) f1 / f2; printf("i2 = %d\n",i2); i3 = f1 / (int) f2; printf("i3 = %d\n", i3); i4 = (int) f1 / (int) f2; printf("i4 = %d\n", i4); return 0; } A saída do programa 9.4 é i1 = 7 i2 = 6 i3 = 10 i4 = 10 As primeiras duas atribuições fazem com que as variáveis f1 e f2 recebam as constantes de ponto flutuante 10.8 e 1.5 . Em seguida, a atribuição i1 = f1 / f2; faz com que o resul- tado da expressão aritmética à direita da instrução de atribuição seja atribuído à variável i1 do tipo inteiro. A expressão aritmética devolve um valor de ponto flutuante: 10.8 / 1.5 = 7.2 . Porém, como do lado esquerdo da atribuição temos uma variável do tipo inteiro, a parte fracionária deste resultado é descartada e o valor 7 é então armazenado na variável i1 e mostrado com printf . Na próxima linha, a expressão aritmética do lado direito da atribuição é (int) f1 / f2 que é avaliada como (int) 10.8 / 1.5 = 10 / 1.5 = 6.666666 e, como do lado direito da instrução de atribuição temos uma variável do tipo inteiro i2 , o valor 6 é armazenado nesta variável e mostrado na saída através do printf na linha seguinte. Na próxima linha, a expressão aritmética f1 / (int) f2 é avaliada como 10.8 / (int) 1.5 = 10.8 / 1 = 10.8 e, de novo, como do lado direito da instrução de atribuição temos uma variável do tipo inteiro i3 , o valor armazenado nesta variável é 10 , que também é mos- trado na saída através de printf logo a seguir. E, por fim, a expressão aritmética seguinte é (int) f1 / (int) f2 e sua avaliação é dada por (int) 10.8 / (int) 1.5 = 10 / 1 = 10 e portanto este valor é atribuído à variável i4 e apresentado na saída com printf . FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 95 Um compilador da linguagem C considera qualquer constante com ponto flutuante como sendo uma constante do tipo double , a menos que o programador explicitamente diga o contrário, colocando o símbolo f no final da constante. Por exemplo, a constante 3.1415f é uma constante com ponto flutuante do tipo float , ao contrário da constante 55.726 , que é do tipo double . Uma constante de ponto flutuante também pode ser expressa em notação científica. O valor 1.342e-3 é um valor de ponto flutuante e representa o valor 1,342×10−3 ou 0,001324. O valor antes do símbolo e é chamado mantissa e o valor após esse símbolo é chamado expoente do número de ponto flutuante. O símbolo e pode ser substituído pelo símbolo E , tendo o mesmo efeito. Para mostrar um número com ponto flutuante do tipo double na saída padrão podemos usar o mesmo par de caracteres de conversão de tipo %f que usamos para mostrar na saída um número com ponto flutuante do tipo float . No entanto, para realizar a leitura de um número de ponto flutuante que será armazenado em uma variável do tipo double usamos o par de caracteres %lf , ao invés de %f , como caracteres de conversão de tipo. Esta diferença é sutil, mas importante na linguagem C. Um outro exemplo do uso de constantes e variáveis do tipo ponto flutuante ( float e double ) é mostrado no programa 9.5, que computa a área de um círculo cujo valor do raio é informado pelo usuário em radianos. Programa 9.5: Cálculo da área do círculo. #include <stdio.h> /* Recebe o raio de um círculo e mostra sua área */ int main(void) { float pi; double raio, area; pi = 3.141592f; printf("Digite o valor do raio: "); scanf("%lf", &raio); area = (double) pi * raio * raio; printf("A área do círculo é %f\n", area); return 0; } FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 96 Exercícios Faça a simulação da execução passo a passo das soluções dos exercícios a seguir. 9.1 Dados números reais a, b e c, calcular as raízes de uma equação do 2o grau da forma ax2 + bx+ c = 0. Imprimir a solução em uma das seguintes formas: (a) DUPLA e o valor da raiz; (b) REAIS DISTINTAS e os valores das duas raízes; ou (c) COMPLEXAS e o valor da parte real e da parte imaginária das raízes. Programa 9.6: Uma solução para o exercício 9.1. #include <stdio.h> #include <math.h> /* Recebe três reais a, b e c e mostra as raízes de ax^2 + bx + c = 0 */ int main(void) { float a, b, c, delta; printf("Informe a, b e c: "); scanf("%f%f%f", &a, &b, &c); delta = b * b - 4 * a * c; if (delta == 0) { printf("DUPLA\n") printf("%f\n", -b / (2*a)); } else if (delta > 0) { printf("REAIS DISTINTAS\n"); printf("%f\n", -b - sqrt(delta) / (2*a)); printf("%f\n", -b + sqrt(delta) / (2*a)); } else { delta = -delta; printf("COMPLEXAS\n"); printf("Parte real: %f\n", -b / (2*a)); printf("Parte imaginária: %f\n", sqrt(delta) / (2*a)); } return 0; } Esta solução exige que o programa correspondente seja compilado com a diretiva -lm . 9.2 Uma pessoa aplicou um capital de x reais a juros mensais de y% durante 1 ano. Determi- nar o montante de cada mês durante este período. Exemplo: Se o capital inicial é x = 1000.0 reais e os juros mensais são de y = 1, isto é 1% ao mês, então a saída deve ser Mês 1: 1010.000000 Mês 2: 1020.099976 Mês 3: 1030.301025 Mês 4: 1040.604004 FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 97 Mês 5: 1051.010010 Mês 6: 1061.520142 Mês 7: 1072.135376 Mês 8: 1082.856689 Mês 9: 1093.685303 Mês 10: 1104.622192 Mês 11: 1115.668457 Mês 12: 1126.825073 9.3 Os pontos (x, y) que pertencem à figura H (veja a figura 9.1) são tais que x > 0, y > 0 e x2 + y2 6 1. Dados n pontos reais (x, y), verifique se cada ponto pertence ou não a H . ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� ����������� H y x Figura 9.1: Área H de um quarto de um círculo. 9.4 Considere o conjunto H = H1 ∪H2 de pontos reais, onde H1 = {(x, y)|x 6 0, y 6 0, y + x2 + 2x− 3 6 0} , H2 = {(x, y)|x > 0, y + x2 − 2x− 3 6 0} . Dado um número inteiro n > 0, receba uma sequência de n pontos reais (x, y) e verifique se cada ponto pertence ou não ao conjuntoH , contando o número de pontos da sequência que pertencem a H . 9.5 Para n > 0 estudantes de uma determinada turma, são dadas 3 notas de provas. Cal- cular a média aritmética das provas de cada estudante, a média da turma, o número de aprovados e o número de reprovados, onde o critério de aprovação é média > 5.0. 9.6 O estudo dos números harmônicos iniciou na Antiguidade Clássica (século VIII a.C. ao século V d.C.). Os números harmônicos têm diversas implicações na Teoria dos Números, uma subárea da Matemática, estão estreitamente relacionadosà função zeta de Riemann e aparecem em várias expressões de diversas funções especiais. O n-ésimo número harmônico, denotado porHn, é determinado pela seguinte expressão: Hn = 1 + 1 2 + 1 3 + . . .+ 1 n = n∑ k=1 1 k . Dado um natural n, determine o número harmônico Hn. FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 98 9.7 Dado um natural n, calcular e imprimir o valor da seguinte soma 1 n + 2 n− 1 + 3 n− 2 + . . .+ n 1 . 9.8 Escreva um programa que calcule a soma: 1− 1 2 + 1 3 − 1 4 + . . .+ 1 9999 − 1 10000 pelas seguintes maneiras: (a) adição dos termos da esquerda para a direita; (b) adição dos termos da direita para a esquerda; (c) adição separada dos termos positivos e dos termos negativos da esquerda para a direita; (d) adição separada dos termos positivos e dos termos negativos da direita para a es- querda. 9.9 Uma maneira de calcular o valor do número pi é utilizar a seguinte série: pi = 4− 4 3 + 4 5 − 4 7 + 4 9 − 4 11 + . . . Escreva um programa que calcule e imprima o valor de pi através da série acima, com precisão de 4 casas decimais. Para obter a precisão desejada, adicionar apenas os termos cujo valor absoluto seja maior ou igual a 0.0001. 9.10 Dado umnúmero real x, tal que 0 6 x 6 1, calcular uma aproximação do arco tangente de x em radianos através da série infinita: arctanx = x− x 3 3 + x5 5 − x 7 7 + . . . incluindo todos os termos da série até que |xkk | < 0.0001, para algum k ímpar. 9.11 A base dos logaritmos é o número de Euler e = 2.718281 . . . O número de Euler por vezes também é chamado de constante de Néper, número de Napier ou número neperiano. Uma das tantas maneiras de calcular o valor de ex é usar a seguinte série: ex = x0 + x1 1! + x2 2! + x3 3! + . . . Dados dois números reais x e ε, com 0 < ε < 1, calcular o valor de ex incluindo todos os termos Tk = x k k! , com k > 0, até que Tk < ε, para algum k. Mostre na saída o valor computado e o número total de termos usados na série. 9.12 Dados x real e n natural, calcular uma aproximação para cosx, onde x é dado em radia- nos, através dos n primeiros termos da seguinte série: cosx = 1− x 2 2! + x4 4! − x 6 6! + . . .+ (−1)k x 2k (2k)! + . . . para algum k > 0. Observação: o denominador da série do cosseno cresce muito rapidamente e, por isso, use n 6 6. FACOM UFMS 9 NÚMEROS COM PONTO FLUTUANTE 99 9.13 Dados x e ε reais, com 0 < ε < 1, calcular uma aproximação para sen x, onde x é dado em radianos, através da seguinte série infinita: sen x = x 1! − x 3 3! + x5 5! − . . .+ (−1)k x 2k+1 (2k + 1)! + . . . incluindo todos os termos Tk = x 2k+1 (2k+1)! , com k > 0, até que Tk < ε, para algum k. Observação: o denominador da série do seno cresce muito rapidamente e, por isso, use n 6 6. FACOM UFMS Números com ponto flutuante Constantes e variáveis do tipo ponto flutuante Expressões aritméticas Referências bibliográficas
Compartilhar