Armazenamento de dados (3) - armazenamento e recuperação de números de ponto flutuante na memória
- prefácio
- 3. Armazenamento de ponto flutuante na memória
-
- 3.1 Exemplo de armazenamento de número de ponto flutuante
- 3.2 Regras de armazenamento de ponto flutuante
- 3.3 Regulamentos IEEE 754
- 3.4 Disposições especiais do IEEE 754 para dígitos significativos M
- 3.5 Disposições especiais para o expoente E no IEEE 754
- 3.6 Exemplo 1
- 3.7 Exemplo 2
- 3.8 Exemplo 3
- 3.9 Determine se dois números de ponto flutuante são iguais?
- Resumir
prefácio
Este artigo então aprende o conteúdo relacionado ao armazenamento de dados, principalmente aprendendo o armazenamento e recuperação de números de ponto flutuante na memória.
3. Armazenamento de ponto flutuante na memória
- Números comuns de ponto flutuante: 3,14159, 1E10
- A família de ponto flutuante inclui: tipos float, double, long double
- O intervalo de números de ponto flutuante: definido em float.h
3.1 Exemplo de armazenamento de número de ponto flutuante
int main()
{
int n = 9;
float *pFloat = (float*)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}
À primeira vista, a saída é: 9, 9,0, 9, 9,0
O resultado da execução é mostrado na figura a seguir:
3.2 Regras de armazenamento de ponto flutuante
num e *pFloat são obviamente o mesmo número na memória, mas os resultados da interpretação de números de ponto flutuante e inteiros serão muito diferentes.Para entender esse resultado, você precisa entender como os números de ponto flutuante são representados dentro do computador.
De acordo com o padrão internacional IEEE (Institute of Electrical and Electronics Engineering) 754, qualquer número V de ponto flutuante binário pode ser representado da seguinte forma:
- (-1)^S * M * 2^E
- (-1)^s representa o bit de sinal, quando s=0, V é positivo; quando s=1, V é negativo
- M representa um número significativo, maior ou igual a 1, menor que 2
- 2^E significa bit expoente
por exemplo:
- 5.0 em decimal, escrito em binário é 101.0, que é equivalente a 1.01×2^2
- De acordo com as regras de armazenamento acima, podemos obter s=0, M=1,01, E=2.
- Decimal -5.0, escrito em binário é -101.0, equivalente a -1.01×2^2
- De acordo com as regras de armazenamento acima, s=1, M=1,01, E=2
3.3 Regulamentos IEEE 754
-
Para um número de ponto flutuante de 32 bits, o 1 bit mais alto é o bit de sinal s, os próximos 8 bits são o expoente E e os 23 bits restantes são o significante M.
-
Para números de ponto flutuante de 64 bits, o 1 bit mais alto é o bit de sinal S, os próximos 11 bits são o expoente E e os 52 bits restantes são o significante M.
3.4 Disposições especiais do IEEE 754 para dígitos significativos M
- No regulamento, 1≤M<2, ou seja, M pode ser escrito na forma de 1.xxxxxx, onde xxxxxx representa a parte fracionária
- Ao salvar M no computador, o primeiro dígito desse número é sempre 1 por padrão, portanto, pode ser descartado, e apenas a parte xxxxxx seguinte é salva
- Por exemplo, ao salvar 1.01, apenas 01 é salvo, e quando é lido, o primeiro 1 é adicionado. O objetivo disso é economizar 1 algarismo significativo
- Tomando como exemplo um número de ponto flutuante de 32 bits, restam apenas 23 bits para M. Depois de arredondar o 1 no primeiro dígito, é equivalente a salvar 24 dígitos significativos.
3.5 Disposições especiais para o expoente E no IEEE 754
3.5.1 Armazenar na memória é um requisito do E
E é um inteiro sem sinal (int sem sinal)
- Se E é de 8 bits, seu intervalo de valores é de 0 a 255
- Se E for 11 bits, seu intervalo de valores é 0~2047
No entanto, E em notação científica pode ser negativo, então o IEEE 754 estipula que o valor real de E deve ser adicionado com um número intermediário quando armazenado na memória:
- Para um E de 8 bits, o número do meio é 127
- Para um E de 11 dígitos, o número do meio é 1023
- Por exemplo, o E de 2^10 é 10, então quando é armazenado como um número de ponto flutuante de 32 bits, deve ser armazenado como 10+127=137, ou seja, 10001001
3.5.2 Regulagem de E ao buscar na memória
1. E não é todo 0 ou nem todo 1
- O número de ponto flutuante é representado pelas seguintes regras, ou seja, o valor calculado do expoente E é subtraído de 127 (ou 1023) para obter o valor real, e então o número significativo M é somado com o primeiro 1
- Por exemplo: a forma binária de 0,5 (1/2) é 0,1, pois a parte positiva deve ser 1, ou seja, a vírgula é deslocada para a direita em 1, então é 1,0*2^(-1), e seu código de pedido é -1+127= 126, representado como 01111110
- Se a mantissa 1.0 remover a parte inteira como 0 e preencher de 0 a 23 dígitos de 00000000000000000000000, sua
representação binária será 0 01111110 00000000000000000000000
2. E é todo 0
- O expoente E do número de ponto flutuante é igual a 1-127 (ou 1-1023) é o valor real
- O dígito significativo M não é mais adicionado com o primeiro 1, mas é reduzido a um decimal de 0,xxxxxx. Isso é feito para representar ±0, e números muito pequenos próximos de 0
3. E é todo 1
- Se os dígitos significativos M forem todos 0, significa ± infinito (positivo ou negativo depende do bit de sinal s)
3.6 Exemplo 1
int main()
{
float f = 5.5; //浮点数
101.1 二进制表示
(-1)^0 * 1.011* 2^2 IEEE 745规定
s=0 //代表正数
E=2 //代表指数,左移2位 ,存储是时要+127 =129
M=1.011 //有效数字
0 10000001 01100000000000000000000
0100 0000 1011 0000 0000 0000 0000 0000
0x40 b0 00 00 小端存储
}
Pode-se ver na análise acima que a forma de armazenamento do número de ponto flutuante 5.5 na memória é mostrada na figura a seguir: o
depurador descobriu que o resultado é consistente com o processo de análise e está armazenado em little endian.
3.7 Exemplo 2
int main()
{
float f = 0.5; 浮点数
0.1 二进制表示
(-1)^0 * 1.0*2^-1 IEEE 745规定
S = 0 代表正数
M = 1.0 有效数字
E = -1 代表指数,右移1位 ,存储是要+127 =126
0 01111110 00000000000000000000000
0011 1111 0000 0000 0000 0000 0000 0000
0x3f 00 00 00
return 0;
}
Pode-se ver a partir da análise acima que a forma de armazenamento do número de ponto flutuante 0,5 na memória é mostrada na figura a seguir: o
depurador descobriu que o resultado é consistente com o processo de análise e está armazenado em little endian.
3.8 Exemplo 3
O seguinte é um exemplo de 3.1 para explicar:
int main()
{
int n = 9;
第一步:正数9在内存存储的形式:
00000000000000000000000000001001
float *pFloat = (float*)&n;
第二步:将正数强制转换位浮点型,认为pfloat指向的内容是浮点数
存储在内存中的形式
0 00000000 00000000000000000001001
0000 0000 0000 0000 0000 1001
0x00 00 00 09
s=0
E= -126 因为E是全为0的特殊情况,取出就是1-127固定的
M= 0.00000000000000000001001 后面23位都是小数位
第三步:从内存中取出浮点数
(-1)^0 * 0.00000000000000000001001 * 2^-126
结果为极限接近0的非常小的数
printf("n的值为:%d\n",n); 输出9
printf("*pFloat的值为:%f\n",*pFloat);输出浮点数0.00000
*pFloat = 9.0;
第一步:浮点数9.0的二进制形式:
1001.0
(-1)^0 * 1.001 * 2^3
s=0
E=3 代表指数,左移3位 ,存储是要+127 =130
M=1.001
第二步:浮点数9.0在内存存储的形式:
0 10000010 00100000000000000000000
0100 0001 0001 0000 0000 0000 0000
0x41 10 00 00
第三步:%d打印,上面的补码就是正数的补码了,三码合一
打印原码: 1,091,567,616
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat); 9.0
return 0;
}
Neste ponto, olhando para os resultados, ficará claro à primeira vista:
- Número de ponto flutuante de saída 0.00000, número de ponto flutuante no formulário de armazenamento de memória 0x00 00 00 09, formulário de armazenamento little endian:
- Número positivo de saída 1.091.567.616, número positivo é armazenado na memória na forma de 0x41 10 00 00 e no formato de armazenamento little-endian:
o resultado de saída é consistente com a análise:
3.9 Determine se dois números de ponto flutuante são iguais?
Dois números de ponto flutuante não podem ser julgados diretamente se são iguais ou não, deve-se julgar se a diferença entre eles está dentro de um determinado intervalo, que pode atender aos seus próprios requisitos de uso.
int main()
{
int a = 0;
if (a == 1)//整数可以直接判断
{
}
float b = 0.00001;//基本接近0,但不是0
if (b==0.0)//不能这样判断,会出问题
{
}
}
Resumir
O conteúdo de dados relacionado ao armazenamento é o primeiro ponto de conhecimento no estágio avançado da linguagem C. Está intimamente relacionado à melhoria da modelagem . Também é necessário estar familiarizado com tipos de variáveis, bits de sinal, intervalos de tipos, complemento de código original , etc. Esta parte do conteúdo é mais Tenha em mente a natureza do tipo de armazenamento variável, você não pode tomar os resultados como garantidos, e cada passo do pensamento deve ser baseado nele .
É necessário rever o antigo e aprender o novo e, através desta parte do estudo, fornecer-se uma ideia diferente no futuro programa para encontrar erros.
O próximo artigo começa a aprender o conteúdo avançado de ponteiros.