CCM0118 Computação I

Documentos relacionados
CCM0118 Computação I Curso de Ciências Moleculares Turma 22 Segundo Semestre de 2012 Segunda Prova 25 de outubro de 2012

Programação das Aulas

Aula 12- Variáveis e valores reais

PROGRAMAÇÃO em C. Vitor Valerio de Souza Campos

Working 03 : Conceitos Básicos II

MAC2166 Introdução à Computação

MAC2166 Introdução à Computação para Engenharia Escola Politécnica Segunda Prova 19 de maio de 2008

Laços de repetição for, while, do-while

INTRODUÇÃO À PROGRAMAÇÃO

Sistemas Operacionais e Introdução à Programação. Programação com linguagem C

Aula 8 Comandos de Seleção

DURAÇÃO DA PROVA: 2 horas

MAC2166 Introdução à Computação para Engenharia Escola Politécnica Primeira Prova 05 de abril de 2010

INTRODUÇÃO À COMPUTAÇÃO - RESUMO E EXERCÍCIOS* P2

Representação e erros numéricos

3. Linguagem de Programação C

Working 03 : Conceitos Básicos II

Faculdade Anglo-Americano Curso de Ciência da Computação Linguagem de Programação. Lista de Exercícios 1

Programação I PRG Engenharia de Telecomunicações 2ª Fase Professor: Cleber Jorge Amaral

Representação e erros numéricos

Vírgula flutuante. Tipos float, double, long double. Uso de funções. Exercícios

Representação e erros numéricos

Representação e erros numéricos

Aula 15: Repetição (Parte 3)

Introdução a Programação na Linguagem C.

Linguagem C. Prof.ª Márcia Jani Cícero

Programação 1. Atribuição, operadores aritméticos, entrada de dados. Técnico em Eletrônica Semestre 5 02

Olimpíadas de Informática Aulas preparatórias Introdução a Programação em C.

3. Linguagem de Programação C

Olimpíadas de Informática

Elementos básicos das linguagens de programação

LÓGICA DE PROGRAMAÇÃO PARA ENGENHARIA AMBIENTE DE PROGRAMAÇÃO. Prof. Dr. Daniel Caetano

Erros, Precisão Numérica e Ponto Flutuante

Prática 10 - Funções

Computação para Informática - Prof. Adriano Joaquim de Oliveira Cruz Segunda Aula Prática - 29 de agosto de 2008

MC102 Algoritmos e Programação de Computadores

Programação: Vetores

Mini apostila de Python - Oficina de Vestibulandos. PET Computação - UFPR September 2016

PROGRAMAÇÃO ESTRUTURADA E ORIENTADA A OBJETOS

Universidade Federal de Uberlândia Faculdade de Computação. Linguagem C: Operadores relacionais e lógicos estruturas condicionais If...

Capítulo 4: Condicionais

DCC001 - Programação de Computadores. Lista de Exercícios 02 - Estruturas de Dados Homogêneas (Vetores).

Introdução à Computação

que imprima os n primeiros termos da série de Fibonacci, lembrando que esta série é definida da seguinte forma:

16 Definição e Uso de Funções em Programas

PROGRAMAÇÃO de COMPUTADORES: LINGUAGEM FORTRAN 90/95

GEQ Prof. Paulo R. Coelho. Lista para prova

Lista de Exercícios 2

Declarações. Identificadores e Tipos de Dados Básicos

Capítulo 2: Condicionais. Pontifícia Universidade Católica Departamento de Informática

ACH5531 Introdução à Computação

Introdução a Programação de Jogos

Faculdade de Computação

Métodos Computacionais. Operadores, Expressões Aritméticas e Entrada/Saída de Dados

Universidade Federal do ABC Programação Estruturada Fabrício Olivetti França Lista de Exercícios 02

Instituto de Física Segundo Semestre de Diurno. Prova Substitutiva 15/12/2000

Cálculo Diferencial e Integral I

As funções são blocos de instruções que facilitam o entendimento do código. Sua sintaxe é:

INF1005: Programação 1. Condicionais. 08/03/10 (c) Rogério Rodrigues 1

Programação Estruturada Prof. Rodrigo Hausen VAMOS USAR O LINUX. SE TIVER ENTRADO NO WINDOWS, REINICIE O COMPUTADOR.

JavaScript (ou JScript)

5. Expressões aritméticas

Introdução à Programação Estruturada Parte 2. Material da Prof. Ana Eliza

As bibliotecas iostream e cstdlib permitem a utilização de diversos comandos de entrada e saída e funções básicas.

Exercícios: Vetores e Matrizes

Puca Huachi Vaz Penna

Programação imperativa. 3. Mais funções

Material Didático Proposto

Programação Estruturada Comandos Condicionais (Decisão) Operadores Relacionais

, cosh (x) = ex + e x. , tanh (x) = ex e x 2

Programação científica C++

Lógica e Linguagem de Programação Convertendo um algoritmo em pseudocódigo para a linguagem C Professor: Danilo Giacobo

Aula 08: Repetição (Parte 3)

Conhecendo a Linguagem de Programação C

Disciplina: Algoritmos e Programação Professor: Paulo César Fernandes de Oliveira, BSc, PhD

Lista 2 TP060. Exercícios Vetores

Tabela T1: Tags para comandos de impressão.

DURAÇÃO DA PROVA: 2 horas

Programação Estruturada

Fundamentos de Programação Instituto Federal de Educação, Ciência e Tecnologia do Rio Grande do Norte 15 de maio de 2018.

BCC701 Programação de Computadores I Lista de Exercícios 05: Funções Definidas pelo Usuário

Programação de Computadores I BCC 701 Lista de Exercícios Módulo

Aulas preparatórias Introdução a Programação em Linguagem C

Programação de Computadores

Comandos de desvio de fluxo. Expressões lógicas.

Introdução à Linguagem C. Adaptado de Deise Saccol

Programação Estruturada

Estrutura do programa

Introdução à Computação - aulas 01 e 02 -

Exercícios Repetição

Aula 11: Laços e exercícios

Processamento da Informação

Aula 03: Introdução a C

Instruções, dados e expressões

Notas de Aula Guilherme Sipahi Arquitetura de Computadores

Transcrição:

CCM0118 Computação I Departamento de Ciência da Computação IME-USP Curso de Ciências Moleculares Turma 22 Segundo Semestre de 2012 Segundo Exercício-Programa Prazo de entrega: até 16 de outubro de 2012. Raízes de Equações Quadráticas Escreva um programa em C que calcula as raízes de equações quadráticas. Seu programa deve ler um inteiro n 1 e os coeficientes reais a, b e c de n equações do segundo grau (ax 2 + bx + c = 0, com a 0). O programa deve calcular as raízes de cada equação e imprimir os resultados da maneira especificada a seguir. Impressão dos resultados Para cada equação deve-se imprimir o tipo de suas raízes (reais simples, real dupla ou complexas) e os valores das raízes. No caso de raízes complexas, deve-se imprimir a parte real e a parte imaginária. O exemplo na página seguinte mostra como seu programa deverá funcionar. Nesse exemplo, os números que aparecem sublinhados foram digitados pelo usuário. Todo o resto é a saída do programa. Note que, para cada equação, os valores das raízes são impressos duas vêzes. Isto ocorre porque o programa implementa o cálculo de raízes de duas maneiras diferentes e apresenta os resultados obtidos com as duas implementações. Cálculo das raízes de uma equação quadrática Todos nós aprendemos a resolver equações quadráticas por meio da fórmula de Báskara: x = b ± b 2 4ac 2a Mesmo sendo matematicamente correta, essa fórmula nem sempre fornecerá resultados acurados se os números reais forem representados em ponto flutuante, como geralmente é o caso nos computadores. O problema conhecido como cancelamento catastrófico faz com que a tradução direta da fórmula de Báskara para uma linguagem de programação (como a linguagem C) não seja uma boa maneira de se calcular as raízes da equação quadrática. O problema do cancelamento catastrófico se manifesta numa subtração de dois números reais (representados em ponto flutuante) próximos um do outro. Para entender exatamente que problema é esse, leia a seguinte entrada da Wikipedia: http://en.wikipedia.org/wiki/loss of significance. A fórmula de Báskara é suscetível a cancelamento catastrófico em dois pontos: 1. na soma dos termos b e b 2 4ac ou na subtração desses termos, dependendo do sinal de b, e 2. no cálculo do discriminante (a subtração b 2 4ac, dentro da raiz quadrada). A primeira dessas possibilidades de cancelamento catastrófico pode ser evitada com um rearranjo da fórmula de Báskara. Basta calcular as raízes da maneira indicada na seção Floating-point implementation (http://en.wikipedia.org/wiki/quadratic equation#floating-point implementation) da 1

Digite o número de equaç~oes: 8 --- Equaç~ao 1 --- c: -3 raizes simples: 3 e -1 (3 e -1, pela fórmula de Báskara) --- Equaç~ao 2 --- c: 10 raizes complexas: 1+3i e 1-3i (1+3i e 1-3i, pela fórmula de Báskara) --- Equaç~ao 3 --- c: 1 raiz dupl (1, pela fórmula de Báskara) --- Equaç~ao 4 --- a: 7.18 b: 43.75 c: -31.21 raizes simples: 0.645079 e -6.73839 (0.645079 e -6.73839, pela fórmula de Báskara) --- Equaç~ao 5 --- a: 3 b: -18 c: 27 raiz dupla: 3 (3, pela fórmula de Báskara) --- Equaç~ao 6 --- a: 0 b: 10 c: 20 *** Erro: o coeficiente a n~ao pode ser zero *** --- Equaç~ao 7 --- b: 2 c: 3 raizes complexas: -1+1.41421i e -1-1.41421i (-1+1.41421i e -1-1.41421i, pela fórmula de Báskara) --- Equaç~ao 8 --- b: 0 c: -2 raizes simples: 1.41421 e -1.41421 (1.41421 e -1.41421, pela fórmula de Báskara) entrada da Wikipedia sobre a equação quadrática. É isso que você deve fazer neste EP. Visite também a página http://introcs.cs.princeton.edu/java/91float/ e veja o exercício 17 ( Quadratic formula ) da lista de Creative exercises ao final dessa página. A segunda possibilidade de cancelamento catastrófico não pode ser evitada com um rearranjo da fórmula de Báskara. Felizmente é possível provar que, no pior caso, um cancelamento catastrófico na subtração b 2 4ac pode acarretar a perda de no máximo a metade dos dígitos significativos do 2

resultado da subtração. Assim sendo, tal cancelamento não trará prejuízo algum (não tornará menos acurados os resultados finais) se no cálculo do discriminante b 2 4ac usarmos o dobro dos dígitos significativos empregados no restante do programa. Neste EP você também deve tomar esse cuidado. Na maior parte do programa você trabalhará com floats. Os coeficientes de cada equação quadrática serão guardados em variáveis do tipo float. As raízes das equações quadráticas (ou a parte real e a parte imaginária de cada raiz, no caso de raízes complexas) também serão floats. No cálculo do discriminante, entretanto, deve ser usado o tipo double. Todas as operações aritméticas que o programa efetuará para calcular o discriminante (três multiplicações e uma subtração) devem ter operandos do tipo double. Pelo que foi dito nos dois parágrafos anteriores, fica claro que seu programa deve implementar um método cuidadoso para calcular as raízes de cada equação. Esse método evita a primeira possibilidade de cancelamento catastrófico e se previne contra a eventualidade de perda de dígitos significativos em conseguência da segunda possibilidade de cancelamento catastrófico. Para efeito de comparação, seu programa deve implementar também um método ingênuo que simplesmente aplica a fórmula de Báskara, sem tomar nenhum cuidado com cancelamento catastrófico. Os valores das raízes de cada equação devem ser impressos duas vêzes primeiro os valores obtidos pelo método cuidadoso, depois os obtidos pela aplicação direta da fórmula de Báskara. Note que, em todas as equações do exemplo da página anterior, o método cuidadoso e a fórmula de Báskara produziram os mesmos resultados. Isso não vai acontecer sempre! Depois de ter seu programa em funcionamento, procure valores dos coeficientes a, b e c que façam os dois métodos produzirem resultados diferentes porque a primeira possibidade de cancelamento catastrófico se manifestou. Procure também valores desses coeficientes que façam os dois métodos produzirem resultados diferentes porque a segunda possibidade de cancelamento catastrófico se manifestou. Teste de igualdade de números reais em ponto flutuante Pelos motivos que já foram discutidos em classe, em geral não se deve usar == para comparar números reais em ponto flutuante: if (x == y) { /* N~ao! */ Este fragmento de programa é ainda pior: if (x - y == 0) { /* N~AO!!! */ O código acima subtrai os números que se deseja comparar e usa == para ver se o resultado é zero. Essa é uma péssima idéia, pois o valor comparado com zero é o resultado de uma subtração na qual pode ocorrido cancelamento catastrófico! Em alguns (poucos) pontos do EP você precisará verificar se dois números em ponto flutuante são (aproximadamente) iguais. Para fazer isso, use a função neary equal, cujo código é fornecido em seguida. Embora essa função receba parâmetros do tipo double, ela pode ser usada para fazer comparações de floats e para fazer comparações de doubles. 3

#include <math.h> /* fabs */ typedef enum {FALSE, TRUE boolean; boolean nearly_equal(double x, double y, double min, double epsilon) { double diff; if (x == y) { return TRUE; else { diff = fabs(x - y); x = fabs(x); y = fabs(y); if (x == 0 y == 0) { /* Relative error makes sense in this case? */ /* No, use absolute error */ return diff < min / 2; else { /* Yes, use relative error */ return diff < epsilon * ((x < y)? x : y); Para comparar dois valores do tipo float, faça uma chamada a nearly equal com os parâmetros min e epsilon iguais às constantes FLT MIN e FLT EPSILON: if (nearly_equal(x, y, FLT_MIN, FLT_EPSILON)) { Para comparar dois valores do tipo double, faça uma chamada a nearly equal com os parâmetros min e epsilon iguais às constantes DBL MIN e DBL EPSILON: double x, y; if (nearly_equal(x, y, DBL_MIN, DBL_EPSILON)) { As constantes FLT MIN, FLT EPSILON, DBL MIN e DBL EPSILON estão definidas em <float.h> e correspondem aos seguintes números: FLT MIN é o menor float positivo normalizado. FLT EPSILON é a distância de 1.0 ao menor float maior que 1.0. DBL MIN é o menor double positivo normalizado. DBL EPSILON é a distância de 1.0 ao menor double maior que 1.0. Para mais informações sobre teste de igualdade em ponto flutuante, veja estas páginas: http://floating-point-gui.de/errors/comparison/ (contém informações básicas) http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ (faz uma discussão mais aprofundada) 4

Mesmo usando a função nearly equal, você deve continuar evitando comparações com resultados de operações suscetíveis a cancelamento catastrófico. Neste EP, por exemplo, quando você quiser verificar se uma equação quadrática tem raiz dupla, chame nearly equal para comparar b 2 e 4ac e não para comparar b 2 4ac e zero! Cálculo da raiz quadrada de um número real não negativo Neste EP você não usará a função sqrt(x) da biblioteca math.h. Seu programa deve ter obrigatoriamente uma função com protótipo double square_root(double x); que calcula a raiz quadrada de x usando o método de Newton, descrito a seguir. Note que a função square root recebe um argumento do tipo double e devolve um valor do tipo double. O cálculo da raiz quadrada deve ser feito com precisão dupla. (Além de usar precisão dupla no cálculo do discriminante, seu programa também trabalhará com doubles quando estiver calculando uma raiz quadrada.) O método de Newton. Suponha que desejamos extrair a raiz quadrada de um número real x > 0. Escolhe-se como chute inicial para x o número r 0 = x e calcula-se a seguinte seqüência de números: r n+1 = 1 (r n + x ) n = 0, 1, 2,... 2 rn (Ou seja: obtemos r 1 = 1 (r 0 + x ) = 1 2 r0 2 a partir de r 1 obtemos r 2, e assim por diante. converge para x.) ( x + x ) x = x + 1, 2 É possível provar que essa sequência de números Esse processo deve ser repetido enquanto r n e r n+1 não forem suficientemente próximos. A aproximação de x será o primeiro valor r n+1 que for suficientemente próximo de r n. Como critério de proximidade, considere que dois valores x e y são suficientemente próximos se a chamada nearly equal(x, y, DBL MIN, DBL EPSILON) devolver TRUE. Questões que você deve responder Coloque num comentário no início do programa, logo após o cabeçalho com seu nome e número USP, suas respostas para as seguintes questões: (a) Para que valores dos coeficientes a, b e c os dois métodos (o método cuidadoso e a aplicação direta da fórmula de Báskara) produziram resultados diferentes porque a primeira possibidade de cancelamento catastrófico se manifestou? Tente achar valores de a, b e c que tornem grande a diferença relativa entre os resultados produzidos pelos dois métodos. (b) Para que valores dos coeficientes a, b e c os dois métodos produziram resultados diferentes porque a segunda possibidade de cancelamento catastrófico se manifestou? Mais uma vez procure valores de a, b e c que maximizem a diferença relativa entre os resultados produzidos pelos dois métodos. Bom trabalho! 5