为什么比较浮动在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
,其中a
和b
是被比较的浮点值, 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和不同的精度,这可能会导致意外的结果,在你的情况。
直接比较float
和double
types的值是不可能的。 在可以比较值之前,有必要将double
转换为float
,或者将float
转换为double
。 如果有人做了前面的比较,那么转换就会问:“ float
是否拥有double
值的最佳float
表示? 如果进行后一种转换,问题将是“ float
是否能够完美地performancedouble
的价值”。 在许多情况下,前一个问题是更有意义的问题,但Java假定float
和double
之间的所有比较都是要问后者的问题。
我会build议,不pipe语言愿意容忍什么,一个编码标准应该绝对禁止直接比较types为float
和double
操作数。 给定的代码如:
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