浮点数在内存中的表示形式及浮点数比较
1 . 浮点数在内存中的表示形式
首先说一下原,反,补,移码。移码其实就等于补码,只是符号相反。对于正数而言,原,反,补码都一样。对负数而言,反码除符号位外,在原码的基础上按位取反;补码则在反码的基础之上,在其最低位上加1;要求移码时,仍然是先求补码,再改符号。浮点数分为float和double,分别占4,8个字节,即32,64位。仅以32位的float为例,并附带说double。
在IEEE754标准中,规定,float的32位这样分: 符号位(S) 1 位;阶码(E) 8 位 ;尾数(M) 23 位。
这里应该注意三点:
A, 阶码是用移码表示的,这里会有一个127的偏移量,它的127相当于0,小于127时为负,大于127时为, 如:10000001表示指数为129-127=2,表示真值为2^2,而01111110则表示2^(-1).
B, 尾数全都是小数点后面的数,
C, 尾数中省略了一个1,因此尾数全为0时,也是1.0...00;
接下来只要说明几个问题就明白了,以123.456为例,表示为二进制就是:N (2) = 1111011. 01110100101111001 ,这里,会右移6位,得到N (2) = 1.111011 01110100101111001*2^6; 这种形式就可以用于上图中的表示格式了:
符号位(S) 0 ;阶码(E) 00000110 ;尾数(M) 11101101110100101111001
阶码移码后: 符号位(S) 0 ;阶码(E) 10000101 ;尾数(M) 11101101110100101111001
即:0x42f6e979
在内存中的存储(大端):
0x00000001 --> 79
0x00000002 --> e9
0x00000003 --> f6
0x00000004 --> 42
2. 浮点数的精度问题
由于在将十进制转为二进制的过程中,常常不能正好转得相等,(当然,像4.0这样的就不会有损失,而1.0/3.0这样的必然损失),所以就产生了浮点数的精度问题。实际上,小数点后的23位二进制数,能影响的十进制数的前8位。
这是为什么呢? 其实很简单,在上面表示的尾数中,是二进制的,小数点后有23位,最后一位的值为1时,它就是1/2^22=0.000000238实际取的时候肯定是0.0000002。也就是说,对于一个float型的浮点数,其有效的位数是从左到右数7位(包括缺省的1才是7位),当到达上面这个第8位时,就不可靠了。
因此将上面的N (2) = 1.111011 01110100101111001*2^6;再转回十进制数时,很可能已经不再是123.456了。
3. 浮点数的比较
为什么浮点数不能直接作“等值比较”? 浮点数的精度问题!
引用林锐《高质量C/C++代码编写指南》的一段话:
【规则4-3-3】不可将浮点变量用“==”或“!=”与任何数字比较。无论float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。假设浮点变量的名字为x,应当将:
if (x == 0.0) // 隐含错误的比较
转化为 :
if ((x>=-EPSINON) && (x<=EPSINON))
其中EPSINON是允许的误差(即精度)。
关于EPSINON,可不是能随便定义的!而且应该能想到,double和float的EPSINON是不同的。定义成什么呢?不必你去定义了,ANSI C已经定义了这些常量:
#include <float.h>
FLT_EPSILON
DBL_EPSILON
LDBL_EPSILON
最后,看一个例子。
#include <stdio.h>
#include <stdlib.h>
main()
{
float f1,f2 ,f3 f4;
double d1, d2, d3, d4;
d1 = 194268.02;
d2 = 194268;
d4 = 0.02;
f1 = 194268.02;
f2 = 194268;
f4 = 0.02;
printf("%f %f %f",f1,f2,f4); //输出--->194268.015625 194268.000000 0.020000
printf("%f %f %f",f1,f2,f4); //输出--->194268.020000 194268.000000 0.020000
printf("%f %f",d1-d2,d4); //输出---> 0.020000 0.020000
printf("%f %f",f1-f2,f4); //输出---> 0.015625 0.020000
if(d1-d2==d4) ////输出---> !=
printf("==");
else
printf("!=");
if(d1-d2==d4) ////输出---> !=
printf("==");
else
printf("!=");
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步