Tipo Real


Resumo:

Um número real no computador deve ter uma representação finita, ou seja, uma variável real é capaz de representar apenas um subconjunto dos números racionais (mas em geral, é possível se aproximar da solução tanto quanto necessário). A forma de representação de números reais no computador é conhecida como ponto flutuante (floating point). As palavras reservadas float e double são utilizadas para declarar variáveis reais, dependendo da precisão desejada (o double oferece maior precisão, o float utiliza menos memória).

Entrada e saída: para ler e imprimir inteiros, utilizamos o %d. Para float utilizado %f, e para double devemos utilizar %lf para leitura e %e, %f ou %g para imprimir.

Expressões: quando o compilador encontra tipos diferentes como operandos de uma operação aritmética (ao menos 1 número real), a operação é calculada como real (o outro operando é promovido). Apenas quando ambos operados de uma operação são inteiros, o resultado é inteiro. Nesse caso, você pode ainda "forçar" que as operações sejam calculadas como reais através do type casting, simplesmente redefinindo o tipo de uma variável (ou constante ou expressão) colocado o tipo desejado explicitamente entre parênteses.

Descrição:

Até o momento nos limitamos ao uso do tipo inteiro para variáveis e expressões. Vamos introduzir agora o tipo real.

Uma variável do tipo real é definida através dos termos double ou float , dependendo da precisão que se queira representar. Como essa precisão é sempre limitada, o conjunto dos números reais que um computador é capaz de representar é na verdade um subconjunto dos números racionais. Vamos primeiro ver como os números dos tipos inteiro e real são representados no computador.

Representação de números inteiros

Os circuitos eletrônicos do computador armazenam a informação na forma binária (também chamada de digital). Um dígito binário pode assumir apenas 2 valores, representados pelos símbolos 0 (zero) e 1 (um), e que nos circuitos podem corresponder, por exemplo, a uma chave aberta/fechada, a um capacitor carregado/descarregado, etc. Esse elemento básico é conhecido com bit.

Os bits (dígitos binários) podem ser combinados para representar números da mesma forma que os dígitos decimais (dígitos de zero a nove), através de uma notação posicional, ou seja, o número 12 na base decimal equivale ao resultado da expressão . Essa mesma quantia pode ser representada por 1100 na base binária pois equivale ao resultado da expressão .
Por razões históricas, a memória do computador é dividida em bytes (conjunto de 8 bits), por isso a memória do seu computador pode ter, por exemplo, 128MB (mega bytes, onde 1MB = bytes) e o disco rígido 40 GB (giga bytes, onde 1GB = bytes). Com um byte, é possível representar valores, por exemplo, de 0 a 255, ou de -128 a +127. Com 16 bits ou 2 bytes é possível representar valores (de -32768 a +32767) e, com uma palavra (conjunto de bits) de 32 bits, (de -2147483648 a +2147483647). Atualmente, boa parte dos computadores pessoais trabalham com palavras de 32 bits (embora já seja comum encontrar máquinas de 64 bits).

Na linguagem C, ao declararmos uma variável, o compilador reserva na memória o espaço necessário para representá-la. Como esse espaço é fixo (por exemplo, 32 bits), é possível que durante uma computação o número de bits utilizado não seja suficiente para representar os valores necessários, e nesse caso, os resultados são, obviamente, inválidos.

Dependendo do maior/menor número que seu programa precisa representar, além de int você pode declarar variáveis inteiras como long (para usar palavras de 64 bits), short (para usar palavras de 16 bits) e cada uma dessas como unsigned, para representar só números positivos, ou seja, um unsigned short é capaz de representar números de 0 a . Nesse curso introdutório, basta você saber utilizar o tipo int.

Representação de números reais

Os tipos de dados inteiros servem muito bem para a maioria dos programas, contudo alguns programas orientados para aplicações matemáticas freqüentemente fazem uso de números reais (ou em ponto flutuante). Para este tipo de dados, em C, podemos utilizar os tipos float e double .

Na memória do computador não podemos armazenar 1/2 bit (apenas os zeros e uns). Como então representar um número fracionário, ou real? A representação é análoga à notação científica, feita em ponto flutuante. Essa notação permite a representação de uma faixa bastante grande de números, como por exemplo:

Número Notação Científica base expoente
1,000,000,000 ou 1e9 1 10
123,000 ou 1.23e5 123 6
456.78 ou 4.5678e2 45678 3
0.00123 ou 1.23e-3 123 -2

Note que o "ponto flutuante" corresponde à posição do ponto decimal, que é "ajustado" pelo valor do expoente, e que nesse exemplo tanto a base como o expoente são agora números inteiros. Uma notação semelhante pode ser utilizada para números binários, e reservamos espaço na memória (ou bits de uma palavra) para armazenar a base e o expoente. Da mesma forma que os inteiros, os números em ponto flutuante são armazenados como um conjunto de bytes, de modo que a sua precisão é limitada.

Normalmente o tipo float tem uma precisão de 6 a 7 casas decimais com o expoente variando entre a e o tipo double uma precisão de 15 casas decimais com expoente variando entre a ocupando um espaço maior para armazenar um valor na memória (em geral, 64 bits). Isto significa que um número como 123456.78901234 será armazenado apenas como 1.234567e6 em uma variável do tipo float ficando o restante além da precisão possível para a representação.

Entrada e saída

O formato de entrada e saída para números reais é semelhante ao de números inteiros, para a imprimir valores reais em C basta utilizar uma das seguintes seqüêcias:

%e imprime um valor real em notação científica
%f imprime um valor real em notação decimal
%g imprime um valor real na notação científica ou decimal, como for mais apropriada

Por exemplo:

include <stdio.h>
include *lt;stdlib.h>

int main ()
{
/* Declarações */
float f = 3.141592654;
double d = 0.00003141592654;
printf("formato e: f=%e \t d=%e\n", f, d);
printf("formato f: f=%f \t d=%f\n", f, d);
printf("formato g: f=%g \t d=%g\n", f, d);
/* FIM */
system ( "pause" );
return 0;
}
A saída desse programa é:
formato e: f=3.141593e+000    d=3.141593e-005
formato f: f=3.141593 d=0.000031
formato g: f=3.14159 d=3.14159e-005
Constantes em ponto flutuante podem ser definidas de diversas formas. A mais geral é uma série de dígitos com sinal, incluindo um ponto decimal, depois um 'e' ou 'E' seguido do valor do expoente (a potência de dez) com sinal. Por exemplo: -1.609E-19 e +6.03e+23. Essas constantes podem ser utilizadas em expressões como por exemplo:
float x = 3.141595426;
float y = 1.23e-23;
Na definição de constantes pode-se omitir sinais positivos, a parte de expoente e a parte inteira ou fracionária. Por exemplo:
3.14159 .2 4e16 .8e-5 100.

Não se deve usar espaços dentro de um número em ponto flutuante: O número 3.34 E+12 está errado.

Saída formatada

Muitas vezes é útil, para facilitar a visualizaçãdo dos resultados, formatar os dados na saída do programa. Tanto o formato %d quanto o %f podem ser formatados no sentido de reservar um número de dígitos para impressão. Para usar formatação, você pode colocar entre o % e o caractere definindo o tipo o seguinte:

Exemplos:
Considere a variável real cempi = 314.159542 e veja como ela pode ser impressa usando diferentes formatos (as barras verticais facilitam a visualização):

    printf("cempi = |%-8.2f| \n", cempi);
printf("cempi = |%8.2f| \n", cempi);
printf("cempi = |%8.4f| \n", cempi);
printf("cempi = |%8.4f| \n", cempi * 1000);
Saída:
    cempi = |314.16  |
cempi = | 314.16|
cempi = |314.1595|
cempi = |314159.5313|
Observe que 8 casas incluem o ponto decimal, e são suficientes para os primeiros 3 printf's. No último printf esse limite não é obedecido, pois o número a ser impresso ocupa um lugar maior que 8. Observe também que o tipo float perde precisão em torno da 6a casa decimal, daí os últimos digitos de cempi * 1000 não estarem corretos.

Expressões

Ao utilizarmos números reais em nossos programas, é comum misturar constantes e variáveis inteiras com reais em nossas expressões. Para cada operador (+, -, *, /, etc) da expressão, o compilador precisa decidir se a operação deve ser realizada como inteira ou como real, pois como a forma de representação de inteiros e reais é diferente, as operações precisam ser feitas usando a mesma representação. A regra básica é, se os operados tiverem tipos diferentes, a operação é realizada usando o "maior" tipo, ou seja, se um dos operandos for real, o resultado da operação é real, caso contrário, a operação é inteira. Veja a saída do programa abaixo e tente entender o que acontence no 1o e 2o printf:

#include <stdio.h>
#include <stdlib.h>

int main ()
{
int i=4;
int j=5;
int k;
float f = 5.0;
float g;

k = 6*(j/i); /* variável inteira k recebe resultado de expressão inteira */
g = 6*(f/i); /* variável real g recebe resultado de expressão real */
printf("1: k=%d g=%f\n", k, g);

g = 6*(j/i); /* variável real g recebe resultado de expressão inteira */
k = 6*(f/i); /* variável inteira k recebe resultado de expressão real */
printf("2: k=%d g=%f\n", k, g);
system("pause");
return 0;
}
Saída:
1: k=6 g=7.500000
2: k=7 g=6.000000

Lembre-se que em uma atribuição, cada expressão é calculada (lado direito) e o resultado é depois armazenado na variável correspondente, definida no lado esquerdo da atribuição. Nas atribuições antes do 1o printf, o tipo da expressão é o mesmo da variável, mas nas atribuições seguintes, os tipos são diferentes. Observe portanto que o tipo da variável que recebe a atribuição NÃO influencia a forma do C calcular as expressões. Após o cálculo, o resultado é convertido ao tipo da variável (ou seja, inteiro 6 passa a real 6.0 e real 7.5 passa a inteiro 7). É possível forçar a mudança de tipos de um termo dentro de expressão através de definições explícitas conhecidas como type casting. Observe o exemplo abaixo:
#include <stdio.h>
#include <stdlib.h>

int main () {
int i=4;
int j=5;
int k;
float f = 5.0;
float g;

/* variável inteira k recebe resultado de expressão inteira */
k = 6*(j/i);

/* variável real g recebe resultado de expressão inteira,
pois a variável f foi explicitamente convertida para o tipo int */

g = 6*((int)f/i);

printf("1: k=%d g=%f\n", k, g);

/* a constante 6 é promovida a float, e portanto o resultado é real */
/* uma forma mais simples seria definir a constante 6 como 6.0 */
g = (float)6*j/i;

/* variável inteira k recebe resultado de expressão real */
k = 6*(f/i);

printf("2: k=%d g=%f\n", k, g);

system("pause");
return 0;
}
Saída:
1: k=6 g=6.000000
2: k=7 g=7.500000

Exercícios:

Da página http://www.ime.usp.br/~macmulti: Recomendados: tente fazer os exercícios 3, 6, 7 e 11.

Eloiza Sonoda