1、用二进制如何表示浮点型数值
我们再了解二进制如何表达浮点型数值前,需要先了解用二进制如何表示整型数值:用二进制如何表示整型数值
由于计算机只认识0、1二进制,所以与表示整数一样,浮点数值最终也都会被解释为二进制机器码,与整型不同的是,所有由计算机储存的浮点类型,都是通过运算转换为十进制的,所以都是高度近似值,并不可能100%精确。具体规则如下:
- 遵循Ieee754标准(IEEE二进位浮点数算术标准)
- 首位均是符号位,1代表负,0代表正。
3.除去首位,用来表示浮点型的二进制要需要划分为指数位和尾数位(也称作小数位)。
- 不同浮点类型的指数位和尾数位占用长度不一样。
- 二进制转换十进制的指数偏差为:2^(指数位长度-1)-1。
这里所说的指数位、尾数位是十进制转二进制运算的关键,以32位浮点为例,它由1位符号位,8位指数位以及23位尾数位组成,例下面这个32位浮点数:
0100 0010 1101 0110 0101 0001 1100 1111
其中:指数位:100 0010 1;尾数位:101 0110 0101 0001 1100 1111。
从上面可知一下结论:
- 符号位为:0,即正值。
- 32位浮点,故指数偏差值:2^(8-1)-1 = 127。
- 指数位为:100 0010 1,即十进制133。
- 尾数位为:101 0110 0101 0001 1100 1111。
下面我们根据以上结论来运算十进制值,步骤如下:
- 计算指数,指数位减去指数偏差值,即133-127=6
- 计算小数,首先为尾数位前面补充小数点以及隐藏位1得:1.101 0110 0101 0001 1100 1111,而后右移指数6位得:1101 011.0 0101 0001 1100 1111
- 逐位运算,逐位求2的乘方得:
1*(2^6)+1*(2^5)+0*(2^4)+1*(2^3)+0*(2^2)+1*(2^1)+1*(2^0)+小数点+0*(2^-1)+0*(2^-2)+1*(2^-3)+0*(2^-4)+1*(2^-5)+0*(2^-6)+0*(2^-7)+0*(2^-8)+1*(2^-9)+1*(2^-10)+1*(2^-11)+0*(2^-12)+0*(2^-13)+1*(2^-14)+1*(2^-15)+1*(2^-16)+1*(2^-17)
=107.1597824
- 添加符号位得:+107.1597824
由此可知,浮点类型进制转换需要耗费一定的cpu运算,而且并不精确,如果想尽量精确,需要提升浮点类型的位数,例如64位。而且在一定范围外,不同的十进制浮点数可能会转换为相同的二进制浮点数,例如:
float f3 = 423.15243f;
float f4 = 423.15244f;
System.out.println(f3 == f4);
结果为:
true
也就是说我们只能判断两个浮点数的精度差,一般使用f4 - f3 < 0.0001方式来判断两个浮点数是否相等(近似相等)。
2、Java中浮点型如何用二进制表示
在Java语言中,浮点数值分2种:float、double,均是带符号整型。
了解基本数据类型看这里:java有哪8种基本数据类型
这些类型除了长度不一致外,其他规则均按照以上规则,具体如下:
float
内存中占用8个字节,32bit。其中符号位1位,指数位8位,尾数位23位。指数偏差值:2^(8-1)-1 = 127
例如:
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
float f1 = 423.1594f;
float f2 = -423.1594f;
int floatToIntBits1 = Float.floatToIntBits(f1);// 根据IEEE754规则,得到浮点的表示值。
int floatToIntBits2 = Float.floatToIntBits(f2);
System.out.println("正float===" + Integer.toBinaryString(floatToIntBits1));// 转二进制
System.out.println("负float===" + Integer.toBinaryString(floatToIntBits2));
System.out.println("正float===" + Integer.toHexString(floatToIntBits1));// 转十六进制
System.out.println("负float===" + Integer.toHexString(floatToIntBits2));
?}
}
结果如下:
正float===1000011110100111001010001100111
负float===11000011110100111001010001100111
正float===43d39467
负float===c3d39467
double
内存中占用16个字节,64bit。其中符号位1位,指数位11位,尾数位52位。指数偏差值:2^(8-1)-1 = 1023
例如:
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
double d1 = 423453.1597824345;
double d2 = -423453.1597824345;
long doubleToLongBits1 = Double.doubleToLongBits(d1);// 根据IEEE754规则,得到浮点的表示值。
long doubleToLongBits2 = Double.doubleToLongBits(d2);
System.out.println("正double===" + Long.toBinaryString(doubleToLongBits1));// 转二进制
System.out.println("负double===" + Long.toBinaryString(doubleToLongBits2));
System.out.println("正double===" + Long.toHexString(doubleToLongBits1));// 转十六进制
System.out.println("负double===" + Long.toHexString(doubleToLongBits2));
?}
}
结果如下:
正double===100000100011001110110000111010010100011100111100000000110101011
负double===1100000100011001110110000111010010100011100111100000000110101011
正double===4119d874a39e01ab
负double===c119d874a39e01ab