💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### 概述 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&lt;Q&lt;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(); } } ```