Java千百问_06数据结构(025)_用二进制如何表示浮点型数值

来源:互联网 发布:sql注入检测工具 编辑:程序博客网 时间:2024/06/05 18:25

点击进入_更多_Java千百问

1、用二进制如何表示浮点型数值

我们再了解二进制如何表达浮点型数值前,需要先了解用二进制如何表示整型数值:用二进制如何表示整型数值
由于计算机只认识0、1二进制,所以与表示整数一样,浮点数值最终也都会被解释为二进制机器码,与整型不同的是,所有由计算机储存的浮点类型,都是通过运算转换为十进制的,所以都是高度近似值,并不可能100%精确。具体规则如下:

  1. 遵循Ieee754标准(IEEE二进位浮点数算术标准)

  2. 首位均是符号位,1代表负,0代表正。

3.除去首位,用来表示浮点型的二进制要需要划分为指数位尾数位(也称作小数位)。

  1. 不同浮点类型的指数位和尾数位占用长度不一样

  2. 二进制转换十进制的指数偏差为: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。

从上面可知一下结论:

  1. 符号位为:0,即正值

  2. 32位浮点,故指数偏差值:2^(8-1)-1 = 127

  3. 指数位为:100 0010 1,即十进制133

  4. 尾数位为:101 0110 0101 0001 1100 1111。

下面我们根据以上结论来运算十进制值,步骤如下:

  1. 计算指数,指数位减去指数偏差值,即133-127=6

  2. 计算小数,首先为尾数位前面补充小数点以及隐藏位1得:1.101 0110 0101 0001 1100 1111,而后右移指数6位得:1101 011.0 0101 0001 1100 1111

  3. 逐位运算,逐位求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

  4. 添加符号位得:+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

1 0