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

点击进入_更多_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

时间: 2024-12-05 05:44:27

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

Java千百问_06数据结构(013)_数组如何传递

点击进入_更多_Java千百问 1.数组如何传递 在java中,我们可以将数组作为参数传递给方法,方式同传递基本类型参数一致. 了解什么是数组看这里:java中的数组是什么 了解循环数组便利看这里:如何遍历数组 例子: public static void printArray(int[] array) { for (int i = 0; i < array.length; i++) { System.out.print(array[i] + " "); } } 可以通过传递数组

Java千百问_06数据结构(016)_引用类型数组在内存中如何储存

点击进入_更多_Java千百问 1.存放基本类型数组在内存中如何储存 java的数组中可以存放引用类型. 存放引用类型的内存分布相比存放基本类型相对复杂.来看一段存储基本类型的程序: 了解什么是数组看这里:java中的数组是什么 了解数组在内存中的储存看这里:java数组如何存储在内存中 public class TestPrimitiveArray { public static void main(String[] args) { //1.定义数组 int[] numbers; //2.分配

Java千百问_06数据结构(017)_什么是二维数组

点击进入_更多_Java千百问 1.二维数组如何定义 Java语言中,多维数组被看作数组的数组. 了解一维数组看这里:java中的数组是什么 定义方式和一维数组类似,如下: type arrayName[ ][ ]: type [ ][ ]arrayName; 2.二维数组如何初始化 二维数组初始化和一维数组一样,分为静态初始化和动态初始化 静态初始化 Java语言中,由于把二维数组看作是数组的数组,数组空间不是连续分配的,所以不要求二维数组每一维的大小相同.初始化方式如下: int intAr

Java千百问_06数据结构(012)_如何遍历数组

点击进入_更多_Java千百问 1.如何遍历数组 我们在处理数组时,经常使用for循环或foreach循环进行遍历,因为数组中的所有元素类型相同并且数组的大小是已知的. 了解什么是数组看这里:java中的数组是什么 了解for循环看这里:java中如何循环执行 使用for循环遍历 public class TestArray { public static void main(String[] args) { double[] myList = {1.9, 2.9, 3.4, 3.5}; //

Java千百问_06数据结构(023)_基本数据类型在内存中如何存放

点击进入_更多_Java千百问 1.基本数据类型在内存中如何存放 了解基本数据类型看这里:java有哪8种基本数据类型 对于java中的8种基本数据类型,可以通过如下方式赋值给变量赋值. int a = 3; float b = 4.0f; a = a + 2; 8中基本数据是将具体值直接存放在栈中,在发生变更时,将具体值替换为新的值.具体如下: 了解java如何管理内存看这里:jvm是如何管理内存的 了解java堆和栈的区别看这里:java堆和栈有什么区别 对于基本数据类型,并没有基本数据池的

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

点击进入_更多_Java千百问 1.用二进制如何表示整型数值 我们都知道,计算机只认识0.1二进制,我们一般操作的寄存器和存储单元也都只认识二进制,我们称一个二进制为一个bit(位),一般32位计算机的寄存器允许操作32bit的数据,即32个0或1,由于书写过长,我们一般使用十六进制表示(每两个十六进制成为一个byte字节,即8bit=1byte).例如: 1111 1111 1111 1111 1111 1111 1111 1111 = ffffffff 了解32位和64位计算机看这里:32位

Java千百问_06数据结构(015)_数组和普通对象的引用变量有什么区别

点击进入_更多_Java千百问 1.数组和普通对象的引用变量有什么区别 了解什么是数组看这里:java中的数组是什么 对于java的数组来说,只有类型兼容(即属于同一数据类型体系且遵守优先级由低到高原则),才能将数组引用传递给另一数组引用,但仍然不能改变数组长度(仅仅只是调整数组引用指针的指向). 了解数组传递看这里:数组如何传递 public class TestArrayLength { public static void main(String[] args) { int[] numbe

Java千百问_06数据结构(018)_多维数组如何储存在内存中

点击进入_更多_Java千百问 1.多维数组如何储存在内存中 了解一维数组如何储存看这里:java数组如何存储在内存中 从底层来看,数组元素可以存放引用类型,数组也是引用类型的一种.也就是说,在数组元素的内部还可以包含数组(如int[][] numbers = new int[length][]),即二维数组可当作一维数组(数组长度为length)来处理. 了解数组和普通引用对象在内存中的区别看这里:数组和普通对象的引用变量有什么区别 由此我们得出结论: 任何多维数组(维度为n,n>1)都可以当

Java千百问_06数据结构(014)_java数组如何存储在内存中

点击进入_更多_Java千百问 1.数组的内存空间是何时分配的 java中的数组是用来存储同一种数据类型的数据结构,一旦初始化完成,即所占的空间就已固定下来,初始化的过程就是分配对应内存空间的过程.即使某个元素被清空,但其所在空间仍然保留,因此数组长度将不能被改变. 了解什么是数组看这里:java中的数组是什么 当仅定义一个数组变量(int[] numbers)时,该变量还未指向任何有效的内存,因此不能指定数组的长度,只有对数组进行初始化(为数组元素分配内存空间)后才可以使用. 数组初始化分为静