Entender a representação dos números inteiros no computador é extremamente importante para evitar certos problemas de precisão e que podem fazer uma solução “certa” ficar errada. Saber o que acontece quando ocorre um overflow/underflow e os limites de cada tipo de dados é bastante valioso durante a codificação de uma solução.
Os números inteiros com sinal são armazenados no computador utilizando a notação binária complemento de 2 mais 1. Nesta notação, o bit mais significativo indica o sinal se o dígito for zero então o número é positivo, caso contrário, o número é negativo. No caso do número negativo, a magnitude, ou seja, o valor absoluto do número é obtido fazendo o complemento do número mais 1.
Tabela dos números representados com 3 bit na notação complemento de 2 mais 1
Binário
|
Complemento
|
Complemento +1
|
Decimal
|
000
|
0
| ||
001
|
1
| ||
010
|
2
| ||
011
|
3
| ||
100
|
011
|
100
|
-4
|
101
|
010
|
011
|
-3
|
110
|
001
|
010
|
-2
|
111
|
000
|
001
|
-1
|
Problema 1: Maior Inteiro com sinal positivo
O maior inteiro com sinal pode ser obtido fazendo o bit mais significativo igual a 1 e depois fazendo o complemento.
Problema 2: Menor Inteiro com sinal positivo
O menor inteiro com sinal pode ser obtido fazendo o bit mais significativo igual a 1.
#include <stdio.h>
#include <stdlib.h>
int main(){
char a,b;
a = (1<<7);
b = ~(1<<7);
printf("CHAR %2d BIT MIN %20d MAX %d\n",sizeof(a)*8,a,b);
short c,d;
c = (1<<15);
d = ~(1<<15);
printf("SHORT %2d BIT MIN %20d MAX %d\n",sizeof(c)*8,c,d);
int e,f;
e = (1<<31);
f = ~(1<<31);
printf("INT %2d BIT MIN %20d MAX %d\n",sizeof(e)*8,e,f);
long long int g,h;
g = (1LL<<63);
h = ~(1LL<<63);
printf("LONG LONG %2d BIT MIN %20lld MAX %lld\n",sizeof(g)*8,g,h);
}
Saída
CHAR 8 BIT MIN -128 MAX 127
SHORT 16 BIT MIN -32768 MAX 32767
INT 32 BIT MIN -2147483648 MAX 2147483647
LONG LONG 64 BIT MIN -9223372036854775808 MAX 9223372036854775807
No caso do long long int, para encontrar o maior e o menor número representado, nós utilizamos a constante 1LL e depois deslocamos para a esquerda 63 bit. Se não for utilizada essa constante, o compilador vai dar o seguinte aviso:
[Warning] left shift count >= width of type
Problema 4: Maior Inteiro sem sinal
O maior inteiro sem sinal pode ser obtido apenas fazendo o complemento de zero, ou seja, colocando todos os bits setados.
#include <stdio.h>
#include <stdlib.h>
int main(){
unsigned char a;
a = ~0;
printf("CHAR MAX %u\n",a);
unsigned short b;
b = ~0;
printf("SHORT MAX %u\n",b);
unsigned int c;
c = ~0L;
printf("INT MAX %u\n",c);
unsigned long long int d;
d = ~0LL;
printf("LONG LONG MAX %llu\n",d);
}
Saída
CHAR MAX 255
SHORT MAX 65535
INT MAX 4294967295
LONG LONG MAX 18446744073709551615
Problema 5: Inicializando um vetor inteiro com memset
int B[100];
memset(B,1,sizeof(B));
O código acima não inicializa o vetor B com 1. A função memset() preenche a memória por chars não por ints.
#include <stdio.h>
#include <stdlib.h>
int main(){
int INF1 = 0x7FFFFFFF; //constante hexadecimal
// valor = 2147483647
//maior valor inteiro da máquina
int INF2 = ~(1<<31);
// valor = 2147483647
//maior valor inteiro da máquina usando operações bit-a-bit
int INF3 = INF2/2;
// valor = 1073741823
//maior valor inteiro que pode ser multiplicado por 2 sem dar overflow
//Por exemplo, no algoritmo do floyd-warshall tem o seguinte condicao
// if( d[i][j] > d[i][k] + d[k][j])
// este comando pode dar overflow por que d[i][k] e d[k][j] são inicializados com INF
// ou seja, você está somando dois valores INF.
int INF4 = 0x3FFFFFFF;
// valor 1073741823
//maior valor inteiro que pode ser multiplicado por 2 sem dar overflow
int INF5 = 0x3F3F3F3F;
// valor 1061109567
//maior valor inteiro que pode ser multiplicado por 2 sem dar overflow
//que pode ser utilizado para inicializar um vetor com memset
//memset(m,0x3f,sizeof(m));
}
#include <stdlib.h>
int main(){
int INF1 = 0x7FFFFFFF; //constante hexadecimal
// valor = 2147483647
//maior valor inteiro da máquina
int INF2 = ~(1<<31);
// valor = 2147483647
//maior valor inteiro da máquina usando operações bit-a-bit
int INF3 = INF2/2;
// valor = 1073741823
//maior valor inteiro que pode ser multiplicado por 2 sem dar overflow
//Por exemplo, no algoritmo do floyd-warshall tem o seguinte condicao
// if( d[i][j] > d[i][k] + d[k][j])
// este comando pode dar overflow por que d[i][k] e d[k][j] são inicializados com INF
// ou seja, você está somando dois valores INF.
int INF4 = 0x3FFFFFFF;
// valor 1073741823
//maior valor inteiro que pode ser multiplicado por 2 sem dar overflow
int INF5 = 0x3F3F3F3F;
// valor 1061109567
//maior valor inteiro que pode ser multiplicado por 2 sem dar overflow
//que pode ser utilizado para inicializar um vetor com memset
//memset(m,0x3f,sizeof(m));
}
Nenhum comentário:
Postar um comentário