1.简介
对于浮点类型的数据采用单精度类型(float,4字节)和双精度类型(double,8字节)来存储。根据国际标准IEEE 754标准规定,无论是单精度还是双精度在存储中都分为三个部分:
(1)符号位(Sign) : 0代表正,1代表为负
(2)指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
(3)尾数部分(Mantissa):尾数部分
2.单精度与双精度
float和double类型:
(1)float类型(32位,4字节)有一个符号位(S),有8个指数位(E),和23个有效数字位(M)
(2)double类型(64位,8字节)有一个符号位(S),有11个指数位(E),和52个有效数字位(M)
S | E | M | 公式 | 偏移量 | |
---|---|---|---|---|---|
单精度浮点 | 1(第31位) | 8(30到23位) | 23(22到0位) | (-1)^S*2(E-127)*1.M | 127 |
双精度浮点 | 1(第63位) | 11(62到52位) | 52(51到0位) | (-1)^S*2(E-1023)*1.M | 1023 |
3.表示范围
浮点数的表示有一定的范围(受限于float和double大小),超出范围时会产生溢出(Flow),一般称大于绝对值最大的数据为上溢(Overflow),小于绝对值最小的数据为下溢(Underflow)。
二进制 | 十进制 | |
---|---|---|
float | ± (2-2^-23) × 2127 | ~ ± 10^38.53 |
double | ± (2-2^-52) × 21023 | ~ ± 10^308.25 |
4.实际举例
举例数据:20.125(D) float类型
进制转换:10100.001(B)
即:(-1)0×1.0100001×24 (乘24就是左移4位,和科学计数法10n一样)
这里可以知道:
S:0
E:4+127=131(1000 0011)
M:0100001(去掉最前面的1)
下面将位数补齐到32位:
S(1) | E(8) | M(23) |
---|---|---|
0 | 1000 0011 | 0100 0010 0000 0000 0000 000 |
继续将上述二进制数转为16进制数:
0100 0001 1010 0001 0000 0000 0000 0000
0x41 0xa1 0x00 0x00
编写代码测试:
#include <stdio.h>
int main()
{
float val = 20.125;
int *ptr = (int *)&val;
printf("val: 0x%0x\n", *ptr);
return 0;
}
运行结果:
得出结论与运算结果一致。
5.浮点数比较
因为浮点数存在精度的问题,所以两个浮点数a,b(如3.1415 与 3.1415926)不能直接用 == 来判断是否相同,而应该是求他们的
差值跟精度相比较这种方法来判断,如: fabs(a-b) < 0.0001。
代码:
#include <stdio.h>
#include <math.h>
int main()
{
float a = 3.1415;
float b = 3.1415926;
if( fabs(a-b) < 0.00001 )
{
printf("Equal\n");
}
else
{
printf("Not equal\n");
}
return 0;
}
运行结果:
Not equal
修改0.00001->0.0001后代码:
#include <stdio.h>
#include <math.h>
int main()
{
float a = 3.1415;
float b = 3.1415926;
if( fabs(a-b) < 0.0001 )
{
printf("Equal\n");
}
else
{
printf("Not equal\n");
}
return 0;
}
运行结果:
Equal
因此在浮点数比较中精度的选择非常重要。