### 概述
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();
}
}
```
- java演变
- JDK各个版本的新特性
- JDK1.5新特性
- JDK1.6新特性
- JDK1.7新特性
- JDK1.8新特性
- JAVA基础
- 面向对象特性
- 多态
- 方法重载
- 方法重写
- class
- 常量
- 访问修饰符
- 类加载路径
- java-equals
- 局部类
- java-hashCode
- Java类初始化顺序
- java-clone方法
- JAVA对象实例化的方法
- 基础部分
- JAVA基础特性
- JAVA关键字
- javabean
- static
- 日期相关
- final
- interface
- 函数式接口
- JAVA异常
- 异常屏蔽
- try-with-resource资源泄露
- JAVA引用
- WeakReference
- SoftReference
- PhantomReference
- 位运算符
- try-with-resource语法糖
- JDK冷知识
- JAVA包装类
- JAVA基本类型与包装类
- java.lang.Boolean
- java.lang.Integer
- java.lang.Byte
- java.lang.Short
- java.lang.Long
- java.lang.Float
- java.lang.Double
- java.lang.Character
- 日期相关
- TemporalAdjusters
- String
- 字符串常量池
- String拼接
- String编译期优化
- StringBuilder&StringBuffer
- intern
- 注解
- java标准注解
- 内置注解
- 元注解
- 自定义注解
- 注解处理器
- JVM注解
- Java8 Annotation新特性
- 反射-Reflective
- Reflection
- Class
- Constructor
- Method
- javabean-property
- MethodHandles
- 泛型
- 类型擦除
- bridge-method
- Accessor&Mutator方法
- enum
- JAVA数组
- finalize方法
- JAR文件
- JAVA高级编程
- CORBA
- JMX
- SPI
- Java SPI使用约定
- ServiceLoader
- 实际应用
- IO
- 工具类
- JDK常用工具类
- Objects
- System
- Optional
- Throwable
- Collections
- Array
- Arrays
- System
- Unsafe
- Number
- ClassLoader
- Runtime
- Object
- Comparator
- VarHandle
- 数据结构
- 栈-Stack
- 队列(Queue)
- Deque
- PriorityQueue
- BlockingQueue
- SynchronousQueue
- ArrayBlockingQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- ConcurrentLinkedQueue
- 列表
- 迭代器
- KV键值对数据类型
- HashMap
- TreeMap
- Hash冲突
- ConcurrentHashMap
- JDK1.7 ConcurrentHashMap结构
- jdk7&jdk8区别
- 集合
- Vector
- Stack
- HashSet
- TreeSet
- ArrayList
- LinkedList
- ArrayList && LinkedList相互转换
- 线程安全的集合类
- 集合类遍历性能
- 并发容器
- CopyOnWriteArrayList
- ConcurrentHashMap
- 同步容器
- BitMap
- BloomFilter
- SkipList
- 设计模式
- 设计模式六大原则
- 单例模式
- 代理模式
- 静态代理
- 动态代理
- JDK动态代理
- cglib动态代理
- spring aop
- 策略模式
- SpringAOP策略模式的运用
- 生产者消费者模式
- 迭代器模式
- 函数式编程
- 方法引用
- 性能问题
- Lambda
- Lambda类型检查
- Stream
- findFirst和findAny
- reduce
- 原始类型流特化
- 无限流
- 收集器
- 并行流
- AOP
- 静态织入
- aspect
- aspect的定义
- AspectJ与SpringAOP
- 动态织入
- 静态代理
- 动态代理
- JDK动态代理
- CGLib动态代理
- Spring AOP
- SpringAOP五种通知类型
- @Before
- @AfterReturning
- @AfterThrowing
- @After
- @Around
- Aspect优先级
- SpringAOP切点表达式
- within
- execution
- 嵌套调用
- 系统优化与重构
- 重叠构造器模式
- 工具类构造器优化
- 常见面试题
- new Object()到底占用几个字节
- 访问修饰符
- cloneable接口实现原理
- 异常分类以及处理机制
- wait和sleep的区别
- 数组在内存中如何分配
- 类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式
- 类的实例化顺序
- 附录
- JAVA术语
- FAQ
- 墨菲定律
- 康威定律
- 软件设计原则
- 阿姆达尔定律
- 字节码工具
- OSGI