1)问:包装类Float中为什么有两个常量来表示最小值:MIN_VALUE和MIN_NORMAL
① MIN_VALUE:最小正非零值常量,是非规格化浮点数所能表示的最小值。值为 3.4E-45 的常量。
② MIN_NORMAL:最小正标准值常量,是规格化浮点数所能表示的最小值,即 2^-126。
可以看出,定义中“格式化”是MIN_VALUE和MIN_NORMAL ,不同的关键因素。
分析:
在计算机中浮点数是由符号,指数和尾数组成。
同一个数字可以有多种表达方式111.11可以表示为1.1111*10^2也可以表示为0.11111*10^3,计算机要进行计算处理就必须要有固定的表达方式,否则计算起来会很影响效率,因此需要规划范表示浮点数,规范化以后表示为±1.f×2E−127,f是尾数,E是指数,由于整数部分固定为1,所以可以省略。
以单精度为例,指数位为8位,尾数位为23位,由于整数部分1固定23位的尾数可以表示24位,所以可以得出结论:
一个int值从第一个1到最后一个1为止的位数超过24,则该值不能被float精确表示。
因为指数部分为了表示负数,所以采用偏移值的编码方式,将8位255一分为二,[ 1,127 ) 是负数,[ 127, 254 ] 是正数,0和255有特殊用途。所以最小的正规化表示为2^-126也就是MIN_NORMAL。
由于在指数运算中可能出现的浮点数对应的指数小于-126,导致无法进行规范化保存,如果按规范化去表示,可能导致一个非零值变为零值,为了解决这种问题,IEEE 标准中引入了非规范(Denormalized)浮点数。规定当浮点数的指数为允许的最小指数值,尾数不必是规范化的,这样可以保存更小的尾数,MIN_VALUE为能保存到的最小的非零值,就是MIN_NORMAL*2-23,也就是尾数1右移23位。
2)问:double a = 1.0-0.9的结果不精确等于0.1,为什么?
浮点数在计算机中进行加减运算时,需要经过零值检测、对阶操作、尾数求和、规格化操作等操作,精度可能丢失。
float和double只能用来做科学计算或者是工程计算。
NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。
验证:
double a = 1.0-0.9;//0.09999999999999998 double b=1,c=1.0; System.out.println(b==c);//true double d=0.09999999999999998;//0.09999999999999998 double e=1/10; System.out.println("e="+e);//0.0 //float f=0.09999999999999998;不兼容,失精度 float g=0.09999999999999998f;//0.1 System.out.println(new BigDecimal(0.1));//0.1000000000000000055511151231257827021181583404541015625 System.out.println(new BigDecimal("1").subtract(new BigDecimal("0.9")));//0.1