Baixe o app para aproveitar ainda mais
Prévia do material em texto
Ju d so n S an to s S an ti ag o TIPO PONTO-FLUTUANTE Tipos Básicos de Dados Introdução O segundo maior grupo de tipos básicos de dados são os tipos ponto-flutuante Números em ponto-flutuante são números com uma parte fracionária (números reais) Ex.: 2.5, 3.14159, 122442.32 Tipos ponto-flutuante fornecem uma faixa de valores maior que os tipos inteiros Se um número é muito grande para o tipo long long, pode-se utilizar um ponto flutuante Introdução O computador armazena um número real em duas partes: um valor (mantissa) e um fator de escala (expoente) Os números 34.1245 e 34124.5 são idênticos a não ser pela posição da sua vírgula 0.341245 100 0.341245 100000 Ponto-Flutuante Valor Escala 34.1245 34124.5 = = Introdução Na memória, o fator de escala não é armazenado como um multiplicador, mas sim como um expoente 0.341245 * 102 = 34.1245 0.341245 * 105 = 34124.5 0.341245 2 0.341245 5 Ponto-Flutuante Mantissa Expoente 34.1245 34124.5 = = Tipos Ponto-Flutuante A linguagem C++ tem três tipos ponto flutuante: float double long double A principal diferença entre os tipos está: Número de dígitos significativos para a mantissa Valor máximo para o expoente Tipos Ponto-Flutuante O que são os dígitos significativos ? 143.06 tem 5 dígitos significativos 4.50 tem 2 dígitos significativos 0.14306 3 0.45 1 143.06 4.5 = = Mantissa Expoente Tipos Ponto-Flutuante Quanto maior a largura de bits usada para: Mantissa: maior a precisão do número Expoente: maior a magnitude do número 0.31415 1 3.1415= Mantissa Expoente Largura de bits = 16 bits 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Tipos Ponto-Flutuante Os tipos ponto-flutuante têm as seguintes larguras de bits na linguagem C++: float tem pelo menos 32 bits double tem pelo menos 48 bits (e é pelo menos tão grande quanto float) long double tem pelo menos o mesmo número de bits que double Mantissa Expoente Largura de bits 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Tipos Ponto-Flutuante Na prática, normalmente os valores são: float tem 32bits double tem 64 bits long double tem 64, 80, 96 ou 128 bits Os valores específicos para uma plataforma podem ser encontrados no arquivo de cabeçalho cfloat #include <cfloat> Tipos Ponto-Flutuante #include <iostream> #include <cfloat> using namespace std; int main() { cout << "Numero de Dígitos Significativos" << endl; cout << "float: " << FLT_DIG << endl; cout << "double: " << DBL_DIG << endl; cout << "long double: " << LDBL_DIG << endl; cout << "Valores Máximos do Expoente" << endl; cout << "float: " << FLT_MAX_10_EXP << endl; cout << "double: " << DBL_MAX_10_EXP << endl; cout << "long double: " << LDBL_MAX_10_EXP << endl; cout << "Numero de Bits na Mantissa" << endl; cout << "float: " << FLT_MANT_DIG << endl; cout << "double: " << DBL_MANT_DIG << endl; cout << "long double: " << LDBL_MANT_DIG << endl; system("pause"); return 0; } Tipos Ponto-Flutuante A saída do programa (Linux/g++): Número de Dígitos Significativos float : 6 double : 15 long double: 18 Valores Máximos do Expoente float : 38 double : 308 long double: 4932 Número de Bits na Mantissa float : 24 double : 53 long double: 64 Tipos Ponto-Flutuante A saída do programa (Windows8/VC++2012): Número de Dígitos Significativos float : 6 double : 15 long double: 15 Valores Máximos do Expoente float : 38 double : 308 long double: 308 Número de Bits na Mantissa float : 24 double : 53 long double: 53 Tipos Ponto-Flutuante Os tipos int e float ambos têm 32 bits, mas o computador representa-os de forma completamente diferente na memória 0 8 bits (expoente) 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 1 1 1 1 1 0 0 23 bits (mantissa) 0 0 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 float (32 bits) = 0.15625 int (32 bits) = 1042284544 1 bit (sinal) Constantes Ponto-Flutuante Uma constante ponto-flutuante pode ser representada de duas formas: Usando a notação decimal padrão Usando a notação exponencial 12.34 // ponto-flutuante 939001.32 // ponto-flutuante 0.00023 // ponto-flutuante 8.0 // também ponto-flutuante 2.52e+8 // pode usar e ou E, + é opcional 8.33E-4 // expoente pode ser negativo 7E5 // o mesmo que 7.0E+05 -18.32e13 // pode ter + ou – na frente Constantes Ponto-Flutuante A notação E: A forma mE+n significa mova o ponto decimal n casas para a direita, e mE-n significa mova o ponto decimal n casas para a esquerda +5.37E+16 Sinal - ou + (opcional) Pode usar E (maiúsculo) ou e (minúsculo) Sinal pode ser +/ - ou omitido Sem espaços Ponto decimal não é necessário se for seguido por zeros Constantes Ponto-Flutuante A notação E garante que um número será representado como ponto-flutuante O sinal da frente se aplica a mantissa, o sinal no expoente se aplica ao fator de escala 70.0 // valor ponto-flutuante 70 // valor inteiro 70E // ponto-flutuante igual a 70.0 -8.33E4 // é igual a -83300 8.33E-4 // é igual a 0.000833 -8.33E-4 // é igual a -0.000833 Precisão do Ponto-Flutuante #include <iostream> using namespace std; int main() { // imprime números sempre com 6 casas decimais cout.setf(ios_base::fixed, ios_base::floatfield); float fltvar = 10.0 / 3.0; // bom para até 6 dígitos double dblvar = 10.0 / 3.0; // bom para até 15 dígitos float milhao = 1.0e6; cout << "float var = " << fltvar; cout << ", vezes um milhao = " << milhao * fltvar << endl; cout << "double var = " << dblvar; cout << ", vezes um milhao = " << milhao * dblvar << endl; system("pause"); return 0; } Precisão do Ponto-Flutuante A saída do programa: A função setf() fixa o número de casas decimais mostradas após a vírgula A variável tipo float garante a precisão para 6 dígitos, a variável double garante a precisão para 15 dígitos float var = 3.333333, vezes um milhao = 3333333.250000 double var = 3.333333, vezes um milhao = 3333333.333333 Precisão do Ponto-Flutuante #include <iostream> using namespace std; int main() { float a = 2.34E+8; float b = a + 1.0f; cout << "a = " << a << endl; cout << "b - a = " << b - a << endl; system("pause"); return 0; } Saída do Programa: a = 2.34e+8 b – a = 0 Ponto-Flutuante Vantagens: Eles podem representar valores entre dois números inteiros Devido ao fator de escala, podem representar uma faixa de valores maior que os tipos inteiros Desvantagens: Operações com pontos-flutuantes são mais lentas que operações com inteiros* Pontos-flutuantes perdem precisão Operadores Aritméticos C++ fornece operadores para cinco cálculos aritméticos básicos: Soma (+) Subtração (-) Multiplicação (*) Divisão (/) Módulo (%) (Resto da Divisão) int rodas = 4 + 2; Expressão Operador Operando Operando Operadores Aritméticos #include <iostream> using namespace std; int main() { float num1, num2; cout << "Entre com um número: "; cin >> num1; cout << "Entre com outro número: "; cin >> num2; cout << "num1 = " << num1 << "; num2 = " << num2 << endl; cout << "num1 + num2 = " << num1 + num2 << endl; cout << "num1 - num2 = " << num1 - num2 << endl; cout << "num1 * num2 = " << num1 * num2 << endl; cout << "num1 / num2 = " << num1 / num2 << endl; system("pause"); return 0; } Operadores Aritméticos A saída do programa: cout mostrao resultado com até 6 dígitos, arredondando o valor se ele tiver mais que 6 dígitos significativos Entre com um número: 50.25 Entre com outro número: 11.17 num1 = 50.25; num2 = 11.17 num1 + num2 = 61.42 num1 - num2 = 39.08 num1 * num2 = 561.292 // 561.2925 num1 / num2 = 4.49866 // 4.498657117278424 Precedência de Operadores Qual o resultado da expressão abaixo? Quando mais de um operador pode ser aplicado ao mesmo operando, C++ usa regras de precedência para decidir qual operador aplicar primeiro: Multiplicação/Divisão/Módulo Soma/Subtração int total = 3 + 4 * 5; // 35 ou 23 int total = 3 + 4 * 5; // 3 + (4 * 5) = 23 Precedência de Operadores Qual o resultado da expressão abaixo? Se os operadores têm a mesma precedência C++ usa regras de associatividade (esquerda-direita ou direita-esquerda) : Multiplicação/Divisão/Módulo (Esquerda-Direita) Soma/Subtração (Esquerda-Direita) int total = 120 / 4 * 5; // 150 ou 6 int total = 120 / 4 * 5; // 150 Operador de Divisão O comportamento do operador de divisão depende dos seus operandos: Se ambos são inteiros é feita a divisão inteira Se um ou ambos são ponto-flutuante, o resultado é a divisão ponto-flutuante 5 / 2 // o resultado é 2 e não 2.5 5.0 / 2 // o resultado é 2.5 5 / 2.0 // o resultado é 2.5 5.0 / 2.0 // o resultado é 2.5 Operador de Divisão #include <iostream> using namespace std; int main() { // sempre mostra 6 casas após a vírgula // cout.setf(ios_base::fixed, ios_base::floatfield); cout << fixed; cout << "Divisão Inteira: 9/5 = " << 9/5 << endl; cout << "Divisão Ponto-Flutuante: 9.0/5.0 = " << 9.0/5.0 << endl; cout << "Divisão Mista: 9.0/5 = " << 9.0/5 << endl; cout << endl; cout << "Constantes double: 1e7/9.0 = " << 1e7/9.0 << endl; cout << "Constantes float: 1e7f/9.0f = " << 1e7f/9.0f << endl; system("pause"); return 0; } Operador de Divisão A saída do programa: O resultado é double se pelo menos um dos operandos é double e float caso contrário O tipo padrão das constantes é double Divisão Inteira: 9/5 = 1 Divisão Ponto-Flutuante: 9.0/5.0 = 1.800000 Divisão Mista: 9.0/5 = 1.800000 Constantes double: 1e7/9.0 = 1111111.111111 Constantes float: 1e7f/9.0f = 1111111.125000 Operador Módulo O operador módulo (%) retorna o resto de uma divisão inteira 5 2 24 1 5 3 13 2 5 6 00 5 Resto da divisão 5 % 2 = 1 5 % 3 = 2 5 % 6 = 5 Operador Módulo #include <iostream> using namespace std; int main() { const int CentavosPorReal = 100; int valor; cout << "Digite um valor em centavos: "; cin >> valor; int reais = valor / CentavosPorReal; int centavos = valor % CentavosPorReal; cout << valor << " centavos corresponde a\n" << reais << " Reais e " << centavos << " centavos." << endl; system("pause"); return 0; } Operador Módulo A saída do programa: Constantes devem ser inicializadas e não podem ter seu valor alterado no programa Digite um valor em centavos: 210 210 centavos corresponde a 2 Reais e 10 centavos const int CentavosPorReal = 100; CentavosPorReal = 200; // atribuição inválida const int CargaHoraria; // deve ser inicializado CargaHoraria = 60; // atribuição inválida Conversões de Tipo A existência de muitos tipos de dados permite ao programador usar o que for mais adequado as suas necessidades short, int, long, long long, char, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long, float, double, long double Para facilitar a linguagem C++ faz muitas conversões automáticas de tipos Conversões de Tipos Conversões automáticas são feitas: Em atribuições de valores à variáveis, quando o valor é de um tipo diferente da variável Em expressões, quando se combinam valores e/ou variáveis de tipos diferentes int valor = 2.5; // 2.5 2 float resultado = 10; // 10 10.0 int total = 2 + 3.5 + 1; // 6.5 6 float resultado = 11/2.0; // 5.5 5.5f Conversões de Tipos Conversões automáticas são feitas: Na passagem de argumentos para funções, quando os argumentos têm tipos diferentes dos parâmetros da função Para entender o resultado de alguns programas é preciso entender as conversões double soma (double, double); // protótipo da função soma(3, 5); // chamada da função: 3 3.0, 5 5.0 Conversões na Atribuição C++ é bastante liberal na atribuição de valores numéricos Atribuir um valor para uma variável com uma largura de bits maior não gera nenhum problema char mar = 102; short sol = mar; // o tipo char é convertido em short 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 char = 8 bits short = 16 bits Conversões na Atribuição É preciso tomar cuidado com atribuições de valores para tipos com menor largura de bits Apenas os bits de mais baixa ordem são copiados quando o tipo de destino tem uma largura menor short sol = 280; char mar = sol; // o valor armazenado é 24 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 0 char = 8 bits short = 16 bits Conversões na Atribuição Potenciais problemas de conversão Tipo de Conversão Problema Potencial Tipo ponto flutuante maior para tipo ponto flutuante menor Ex.: double pra float • Perda de precisão (dígitos significativos) • Valor pode estar fora da faixa do tipo alvo, e neste caso o resultado é indefinido Tipo ponto flutuante para tipo inteiro Ex.: double para int • Perda da parte fracionária • Valor pode estar fora da faixa do tipo alvo, e neste caso o resultado é indefinido Tipo inteiro maior para tipo inteiro menor Ex.: long pra short • Valor original pode estar fora da faixa para o tipo alvo: apenas os bits de mais baixa ordem são copiados Conversões na Atribuição #include <iostream> using namespace std; int main() { // cout.setf(ios_base::fixed, ios_base::floatfield); cout << fixed; float tres = 3; // int convertido para float int aposta = 3.9832; // double convertido para int int debito = 7.2E12; // resultado não definido cout << "tres = " << tres << endl; cout << "aposta = " << aposta << endl; cout << "debito = " << debito << endl; system("pause"); return 0; } Conversões na Atribuição A saída do programa: O valor inteiro foi convertido para float O valor float foi truncado (e não arredondado) A variável debito recebeu um valor muito grande, o resultado obtido está errado tres: 3.000000 aposta: 3 debito: 1634811904 Conversões em Expressões O que acontece se tipos diferentes forem misturados em uma expressão aritmética? Alguns tipos são convertidos automaticamente sempre que eles são usados em expressões Alguns tipos são convertidos apenas quando combinados com outros tipos específicos // val é convertido para double devido ao 2.50 float total = 2.50 * val; char a = 90; char b = 70; int val = a + b; // char é convertido para int Conversões em Expressões Conversão automática em expressões: Os tipos char e short são sempre convertidos para int (isso inclui as versões signed e unsigned) char ch1 = '%'; // % = 37 char ch2 = '&'; // & = 38 // char's para int e o resultado int para char char ch = ch1 + ch2; // K = 75 short galinhas = 20; short patos = 35; // short's para int e o resultado int para short short aves = galinhas + patos; Conversões em Expressões Quando uma operação envolve dois tipos, o menor é convertido para o maior Quando os tipos são iguais não ocorre conversão, mas cuidado // o valor 5 é convertido para double float total = 9.0 / 5; // o valor5 é convertido para long long long long val = 163481190409292 + 5; // ambos os operandos são inteiros // mas o resultado não cabe em um inteiro long long erro = 100000000 * 2009; // -963462912 Conversões em Funções Os protótipos das funções controlam as conversões nas passagens de argumento Aplicam-se as mesmas regras usadas na atribuição de valor para variável float soma(float, float); float a = soma(3,4); // int float // o resultado da função é convertido (float int) int b = soma(3.0, 4.0); // double float float c = soma(3.0f, 4.0f); // nenhuma conversão Type Casts A linguagem C++ permite ao programador forçar conversões de tipos float parcial = 5.4; int resultado = int (3.8) + int (parcial); int total = int (parcial); // estilo C++ int total = (int) parcial; // estilo C cout << int ('A'); cout << char (65); long long bignum = long long (100000000) * 2009; Declarações auto em C++11 C++11 introduz a possibilidade de deduzir o tipo a partir do valor de inicialização Entretanto esta dedução automática não foi concebida para estes casos simples auto n = 100; // n é int auto x = 1.5f; // x é float auto y = 1.3e5; // y é double std::vector<double> vet; std::vector<double>::iterator iv = vet.begin(); std::vector<double> vet; auto iv = vet.begin(); Conclusão Os tipos básicos de dados tipo ponto-flutuante são: float double long double Valores ponto-flutuante são armazenados com uma mantissa e um expoente O arquivo cfloat pode ser consultado para saber os tamanhos de cada tipo Conclusão C++ dispõem de cinco operadores aritméticos: Soma Subtração Multiplicação Divisão (Inteira e Ponto-Flutuante) Módulo Conversões são feitas automaticamente mas também podem ser forçadas via type cast
Compartilhar