为什么比较浮动在Java中不一致?

class Test{ public static void main(String[] args){ float f1=3.2f; float f2=6.5f; if(f1==3.2){ System.out.println("same"); }else{ System.out.println("different"); } if(f2==6.5){ System.out.println("same"); }else{ System.out.println("different"); } } } 

输出:

 different same 

为什么这样的输出? 我期望和第一种情况一样。

不同之处在于,6.5可以完全用浮点数和双精度表示,而3.2不能完全用任何一种types来表示,而且两个最接近的近似值是不同的。 float和double之间的平等比较首先将float转换为double,然后比较两者。 所以数据丢失。


你不应该比较平等或漂浮的比赛。 因为,你不能真正保证你分配给float或double的数字是确切的。 这个舍入误差是浮点计算的一个特征

将无限多的实数压缩成有限数量的比特需要近似表示。 虽然有无限多的整数,但在大多数程序中,整数计算的结果可以存储在32位中。

相比之下,给定任意固定数量的比特,大多数使用实数的计算将产生无法用该比特精确表示的数量。 因此,浮点计算的结果必须经过四舍五入以适应其有限表示。 这个舍入误差是浮点运算的特征。

检查每个计算机科学家应该知道什么更多的浮点运算!

它们都是IEEE浮点标准的不同部分的实现。 一个float是4个字节宽,而一个double是8个字节宽。

作为一个经验法则,在大多数情况下,您应该更喜欢使用double ,只有在有充分的理由时才使用float 。 (一个使用float而不是double的好理由的例子是“我知道我不需要那么高的精度,我需要把它们存储在内存中。”)另外值得一提的是,很难certificate你不需要double精度。

另外,当比较浮点值的相等性时,通常需要使用像Math.abs(ab) < EPSILON ,其中ab是被比较的浮点值, EPSILON是像1e-5那样的小浮点值。 原因在于浮点值很难编码它们“应该”的确切值 – 相反,它们通常编码的值非常接近 – 所以当确定两个值是否相同时,您必须“斜视”。

编辑 :每个人都应该阅读链接@Kugathasan Abimaran张贴如下: 每个计算机科学家应该知道关于浮点算术更多!

要看你在处理什么,你可以使用Float和Double的toHexString方法:

 class Test { public static void main(String[] args) { System.out.println("3.2F is: "+Float.toHexString(3.2F)); System.out.println("3.2 is: "+Double.toHexString(3.2)); System.out.println("6.5F is: "+Float.toHexString(6.5F)); System.out.println("6.5 is: "+Double.toHexString(6.5)); } } $ java Test 3.2F is: 0x1.99999ap1 3.2 is: 0x1.999999999999ap1 6.5F is: 0x1.ap2 6.5 is: 0x1.ap2 

一般来说,如果数字等于A * 2 ^ B,则数字具有精确的表示forms,其中A和B是其允许的值由语言规范设置的整数(并且double具有更多的允许值)。

在这种情况下,
6.5 = 13/2 =(1 + 10/16)* 4 =(1 + a / 16)* 2 ^ 2 == 0x1.ap2,while
3.2 = 16/5 =(1 + 9/16 + 9/16 ^ 2 + 9/16 ^ 3 + …)* 2 ^ 1 == 0x1.999。 。 。 P1。
但是Java只能保存有限的数字,所以它减less了.999。 。 。 在某个时候closures。 (从math中可以记得0.999 … = 1,以10为底数。在16的基数中,它是0.fff。= 1。)

 class Test { public static void main(String[] args) { float f1=3.2f; float f2=6.5f; if(f1==3.2f) System.out.println("same"); else System.out.println("different"); if(f2==6.5f) System.out.println("same"); else System.out.println("different"); } } 

像这样尝试,它会工作。 没有'f'你正在比较浮动与其他浮动types和不同的精度,这可能会导致意外的结果,在你的情况。

直接比较floatdoubletypes的值是不可能的。 在可以比较值之前,有必要将double转换为float ,或者将float转换为double 。 如果有人做了前面的比较,那么转换就会问:“ float是否拥有double值的最佳float表示? 如果进行后一种转换,问题将是“ float是否能够完美地performancedouble的价值”。 在许多情况下,前一个问题是更有意义的问题,但Java假定floatdouble之间的所有比较都是要问后者的问题。

我会build议,不pipe语言愿意容忍什么,一个编码标准应该绝对禁止直接比较types为floatdouble操作数。 给定的代码如:

 float f = function1(); double d = function2(); ... if (d==f) ... 

d表示float不能精确表示的情况下,我们不可能说出什么行为是有意的。 如果意图是将f转换为double ,并将该转换的结果与d进行比较,则应该将比较结果写为

 if (d==(double)f) ... 

尽pipetypes转换不会改变代码的行为,但是它明确表示代码的行为是有意的。 如果意图是比较表明f是否具有d的最佳float表示,则应该是:

 if ((float)d==f) 

请注意,这种行为与没有演员的情况会有很大的不同。 如果您的原始代码将每个比较的double操作数转换为float ,那么两个相等性testing都会通过。

一般来说,由于近似问题,使用带有浮点数的==运算符不是一个好习惯。

6.5可以完全用二进制表示,而3.2不能。 这就是为什么精度上的差异对于6.5而言并不重要,所以6.5 == 6.5f

要快速刷新二进制数字的工作方式:

 100 -> 4 10 -> 2 1 -> 1 0.1 -> 0.5 (or 1/2) 0.01 -> 0.25 (or 1/4) 

等等

6.5二进制: 110.1 (确切的结果,其余的数字只是零)

3.2 in binary: 11.001100110011001100110011001100110011001100110011001101... (这里精度很重要!)

浮点只有24位精度(其余的用于符号和指数),所以:

3.2f二进制: 11.0011001100110011001100 (不等于双精度逼近)

基本上和你写十进制数的1/5和1/7时是一样的:

 1/5 = 0,2 1,7 = 0,14285714285714285714285714285714. 

float的精度比double小,bcoz float使用32位,其中1是用于Sign,23是精度,8是指数。 精度是重要的事情。一个十进制数表示为float和double可以是相等或不相等取决于是否需要精度(即范围小数点后的数字可以变化)。 问候S. ZAKIR