概述

Double遵循IEEE754算数标准

Double遵循此标准中的64位浮点数表示方式。从左到右具体为:

  • 第一位为符号部,0表示正,1表示负
  • 2~12位为指数部,用以存放具体数值的指数
  • 13~64位为尾数部

其中指数部为11位,可以表示2048个数,为-1023~+1024,因为存在正负号,会导致运算比较困难,故标准中设置了一个偏移值,将指数加上偏移值后得到编码值存储在指数部中,利于计算和比较。其中偏移值为2^(x-1)-1,x为指数部的位数,此处为11,故偏移值为1023.得到的编码值范围为0~2047(其中0(11位全是0)和2047(11位全是1)为特殊情况,下面会提到).

规约数:规约数是指数的编码值(假设为Q),0<Q<2047时,所表示的数,此时尾数的个位将自动补全1.例如,十进制下的15用double存储时,可以分以下几步理解:

1.先将15化为2进制,为1111

2.将1111转化为二进制下的指数形式,为1.111* 2^3,故用double存储时,指数为3,加上偏移值后的指数部存储编码值为1026,尾数部为111(小数点前的1自动补全)

3.double中的值为0100 0000 0010 1110(后面还有48个0)

但光用规约数也会产生问题,例如,只用规约数的话正数最小值为1.0* 2^-1022,这会带来很大麻烦,如1.2*2^(-1022)-1.1*2^(-1022)即0.1*2^(-1022)将用Double表示时将为0,值得连续性也会在此处发生断崖式下降(大于1.0* 2^-1022的数,连续性为2^(-1074)),0也无法表示。故需要引入非规约数。

非规约数:指数部的编码值为0,且尾数部不全为0,此时尾数部的整数位将自动补全0.

当一个数为非规约数时,指数编码值为0,实际指数为-1022(没错,是-1022,不是-1023,需要加1,就是这么规定的),此时,double的连续性将处处相等,都为2^(-1074),并且任何两个double的和差都能用唯一的double值表示。

当指数部编码值为0,尾数部也为0时,double值为0,固0可以有两种表达方式(+0和-0)

当指数部编码为2047,尾部全为0时,表示无穷,尾部不是全为0时,表示NaN

此种设计下的double值比较十分方便,首先比较符号位,为0的一定大于为1的(正数大于负数),若相等,再比较指数位,因为存的编码值都为正数,所以编码值大的数一定大(符号位为0的情况下,为1则结果反一下),若还相等,最后比较尾数位,十分高效

源码:

/*实现Comparable接口使Doubel对象变成可比较的对象 */
public final class Double extends Number implements Comparable<Double> {

    /*在java中将 1.0 /2.0 设置为正无穷大即 Infinity*/
    public static final double POSITIVE_INFINITY = 1.0 / 0.0;
    /* 与上面相反 负无穷大 即 -Infinity */
    public static final double NEGATIVE_INFINITY = -1.0 / 0.0;

    /* 将 0.0 /0.0 设置为一个非数字的字符串*/
    public static final double NaN = 0.0d / 0.0;
    /* 设置最大值为1.7976931348623157e+308*/  
    public static final double MAX_VALUE = 0x1.fffffffffffffP+1023; // 1.7976931348623157e+308
Double.longBitsToDouble(0x0010000000000000L)}.

    /* 保存 double 类型的最小正标准值的常量,最小正标准值为 2-1022。它等于十六进制的浮点字面值 0x1.0p-1022,也等于Double.longBitsToDouble(0x0010000000000000L)。 */

    public static final double MIN_NORMAL = 0x1.0p-1022;
    /*指数部最大值为2^1023  */
    public static final int MAX_EXPONENT = 1023;
    /*指数部最小值为2^-1022  */
static final int MIN_EXPONENT = -1022;

   /*设置 长度为64位*/
    public static final int SIZE = 64;
    /* 设置为 8个字节*/
    public static final int BYTES = SIZE / Byte.SIZE;
    /*表示基本类型 double 的 Class 实例。 */
    @SuppressWarnings("unchecked")
    public static final Class<Double>   TYPE = (Class<Double>) Class.getPrimitiveClass("double");
}

重点方法

  • toHexString(double d)将Double的值转换成十六进制,并返回成字符串

    public static String toHexString(double d) {
    
      if (!isFinite(d) ) //判断是否超过double的最大值与最小值
    
          return Double.toString(d);//如果超出了范围就返回他的字符串
      else {
    
          StringBuilder answer = new StringBuilder(24);//声明了一个StringBuilder
    
          if (Math.copySign(1.0, d) == -1.0) //通过Math.copySign 返回的值来判断传入的double值是否为负数,如果是负数就是在上面的StringBuilder中添加一个负号
              answer.append("-");                 
    
          answer.append("0x");//十六进制以0x开头
    
          d = Math.abs(d);//将传入的值进行绝对值转换要是负数的话就变成整数,整数不变
    
          if(d == 0.0) {
              answer.append("0.0p0");//如果传入的值为0.0直接返回0x0.0p0
          } else {  //传进来的值不为0.0
              boolean subnormal = (d < DoubleConsts.MIN_NORMAL);//设置一个布尔变量 判断是否小于DoubleConsts最小值
    
              long signifBits = (Double.doubleToLongBits(d)
                                 & DoubleConsts.SIGNIF_BIT_MASK) |
                    0x1000000000000000L;
              answer.append(subnormal ? "0." : "1.");
      /*隔离低位十六进制的13位数字*/
              String signif = Long.toHexString(signifBits).substring(3,16);
              answer.append(signif.equals("0000000000000") ? // 13 zeros
                            "0":
                            signif.replaceFirst("0{1,12}$", ""));
    
              answer.append('p');
    
              answer.append(subnormal ?
                            DoubleConsts.MIN_EXPONENT:
                            Math.getExponent(d));
          }
          return answer.toString();
      }
    }
    

results matching ""

    No results matching ""