我知道 double型数据在内存的表示遵循IEEE标准,对于0.1 ,1.1,2.1等等 很多数,不能被精确的表示为double数据
只能被表示为最接近它的double值
先来看一段程序
double d1 = 0.9;
double d2 = 0.1;
double d3 = 1.1;
System.out.println(d1);
System.out.println(d2);
System.out.println(d3);
输出为:
0.9
0.1
1.1
输出结果 并没有 变成我们想象的那种 0.99999999999999 或者1.10000000000000001
这说明0.1, 1.1 本身就是double型最接近它们的值。
再来看一段:
System.out.println(5.0 - 4.1);
System.out.println(5.0 - 3.1);
System.out.println(5.0 - 2.1);
System.out.println(5.0 - 1.1);
System.out.println(5.0 - 0.1);
System.out.println("******************");
System.out.println(4.0 - 3.1);
System.out.println(3.0 - 2.1);
System.out.println(2.0 - 1.1);
System.out.println(1.0 - 0.1);
System.out.println("******************");
System.out.println(4.0 - 0.1);
System.out.println(3.0 - 0.1);
System.out.println(2.0 - 0.1);
System.out.println(1.0 - 0.1);
输出结果:
0.9000000000000004
1.9
2.9
3.9
4.9
******************
0.8999999999999999
0.8999999999999999
0.8999999999999999
0.9
******************
3.9
2.9
1.9
0.9
这些结果开始时超出了我的想象
从第一组数据看,相差大于1的,好像结果是对的,
从第二组看,相差小于1的,结果居然也有对的,
从第三组看,和0.1作差的全是对的。
那么 0.1跟1.1,2.1等等其它数有什么不同呢? 相差大于1的时候结果怎么就变对了呢?
问题就出现在0.1 的IEEE表示上,
因为它标准化的时候0.1要小数点被向右移位,而其它数 小数点像左移
这样0.1算的实际位数要比 2.1,3.1等等 其它数多几位, 即0.1本身的double型表示比2.1中的那个0.1要精确。
在做double型减法运算时,需要经过对阶,求和,右规,舍入(0舍1入)操作
如5.0-0.1 对阶需要移动5位,计算舍入后最后得出4.9。这个4.9中的0.9其实是一个不精确的数,但0.9比0.8999999999999或者0.90000000001更接近真实值。
而5.0-4.1对阶时 不需要移动,计算舍入后最后得出0.9000000000000004, 这个数也不是一个精确值,只是因为真实值相对于0.9000000000000003或者0.9000000000000005,跟接近与0.9000000000000004.
假如我的想法正确,那么就是对阶移动位数比较多时,计算机能得出跟数学计算一样的值,否则得出一个其他值。
验证
System.out.println(100.0 - 0.1);
System.out.println(100.0 - 99.1);
99.9
0.9000000000000057
综上,结论是对的。
同样的道理,假如 某个数a 大于2^54; 因为double型的尾数是52位, 加上标准化的一位 共53位,
那么将a转换为double型时,采用恒掉的方法,只能取前53位, 又假如 a的第54位为0, 则(double)a+1 = = (double)a