System.out.println(Math.round(53.5)); // 54System.out.println(Math.round(56.5)); // 57System.out.println(Math.round(0.535*100)); // 54System.out.println(Math.round(0.565*100)); // 56 ?想不明白,问号这里怎么会是56,不是四舍五入嘛?
调试欢乐多
java中浮点数的表示是用IEEE754标准的.以float数为例。float占4个Byte,共32个bit,机内表示是最高位是符号位,下来的8位是指数位,最后23位用来表示小数。
表示指数的8位是以移码的形式存放的,移码就是仅对补码的符号位取反得到的.这个数要看成一个无符号数再减去127.是2的幂次.
表示小数的23位,实际上是表示一个整数部分是1的小数,但整数部分并没有存放在23中,因为无论什么时候都是1,所以不存放也可以.
假设符号位为s,指数部分为e,小数部分为f,则实际的数为:
x=(-1)^s*2^(e-127)*f.
用下面的程序可以把楼主的四个浮点数机内表示打印出来
import java.util.*;
import java.text.*;public class Test{
public static void main(String [] args) {
float a=53.5f,b=56.5f,c=0.535f,d=0.565f;
int ai,bi,ci,di;
ai=Float.floatToIntBits(a);
bi=Float.floatToIntBits(b);
ci=Float.floatToIntBits(c);
di=Float.floatToIntBits(d);
System.out.println(Integer.toBinaryString(ai));
System.out.println(Integer.toBinaryString(bi));
System.out.println(Integer.toBinaryString(ci));
System.out.println(Integer.toBinaryString(di));
System.out.println(Integer.toBinaryString(ai).length());
}
}结果如下:
1000010010101100000000000000000
1000010011000100000000000000000
111111000010001111010111000011
111111000100001010001111010111
31
最高位如果是0都省掉了。
以第一个数01000010010101100000000000000000为例。
符号位是0,8位指数位是10000100,小数部分是:10101100000000000000000,这个小数表示的是1.10101100000000000000000
转成十进制分别是:指数:128+4=132,小数:1+2^-1+2^-3+2^-5+2^-6=1+0.5+0.125+0.03125+0.015625=1.671875
所以实际的数是1.671875*2^(132-127)=1.671875*32=53.5
所以这个数是精确的。一般来讲,一个浮点数的小数部分如果能精确的转为二进制(转换方法是乘二取整)并且不超过23位,这个浮点数就可以精确表示。53.5的小数部分是0.5可以精确的转为二进制的0.1。所以53.5可以精确表示。56.5也同理。
否则是不能精确表示的,比如0.535,用乘二取整,是不可能转为精确的二进制的,这个数在机内也就无法精确的表示。0.565也一样。
精度的损失可能是微小的,但结果可能是致命的,如1,2楼给出的正确结果下,四舍五入就有问题了。更致命的是你不能这样写程序if(0.8f==x/2)来写程序。System.out.println(1.6f/2==0.8);结果会打印出false来。你只能这样写if(Math.abs(0.8-x/2)<1e-7)。
那为什么system.out.println(0.565×100); 等于56.5 ?
如果要四舍五入大家是如何解决的?
钻牛角了,整个小数转为二进制后,再移位成:1.XXXXX的形式,移位数保存在30~23bit,xxxxx这部分保存在22~0bit