41
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

为什么输出是这样的?我期望same作为第一种情况的结果。

4

8 回答 8

41

不同之处在于 6.5 可以用 float 和 double 精确表示,而 3.2 不能用任何一种类型精确表示。并且两个最接近的近似值是不同的。

float 和 double 之间的相等比较首先将 float 转换为 double,然后比较两者。所以数据丢失。


你永远不应该比较浮点数或双精度数是否相等;因为您不能真正保证分配给 float 或 double 的数字是准确的。

这种舍入误差是浮点计算的一个特征

将无限多个实数压缩为有限位数需要近似表示。尽管整数有无限多,但在大多数程序中,整数计算的结果可以存储在 32 位中。

相反,给定任何固定位数,大多数实数计算将产生无法使用那么多位精确表示的量。因此,浮点计算的结果必须经常四舍五入以适应其有限表示。这种舍入误差是浮点计算的特征。

查看每位计算机科学家应了解的有关浮点运算的更多信息!

于 2013-05-18T18:58:06.847 回答
25

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

根据经验,您可能更喜欢double在大多数情况下使用,并且仅float在有充分理由时使用。float(与 a相对的一个很好的使用理由的例子double是“我知道我不需要那么精确,我需要将一百万个它们存储在内存中。”)还值得一提的是,很难证明你不这样做不需要double精确。

此外,在比较浮点值是否相等时,您通常需要使用类似Math.abs(a-b) < EPSILONwhereabare 被比较的浮点值,并且EPSILON是一个小的浮点值,例如1e-5. 这样做的原因是浮点值很少编码它们“应该”的确切值——相反,它们通常编码一个非常接近的值——所以当你确定两个值是否相同时,你必须“眯着眼睛”。

编辑:每个人都应该阅读下面发布的链接@Kugathasan Abimaran:每个计算机科学家应该了解的关于浮点运算的更多信息!

于 2013-05-18T18:55:14.243 回答
5

要查看您正在处理的内容,您可以使用FloatDouble的 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,则它具有精确的表示形式,其中 A 和 B 是整数,其允许值由语言规范设置(并且 double 具有更多允许值)。

在这种情况下,
6.5 = 13/2 = (1+10/16)*4 = (1+a/16)*2^2 == 0x1.ap2,而
3.2 = 16/5 = ( 1 + 9/16 + 9/16^2 + 9/16^3 + . . . ) * 2^1 == 0x1.999。. . p1。
但是 Java 只能保存有限数量的数字,因此它会削减 .999。. . 在某个时候关闭。(您可能记得数学中的 0.999...=1。这是以 10 为底数。以 16 为底数,它将是 0.fff...=1。)

于 2013-05-22T15:35:33.047 回答
3
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”,您将浮动与其他浮动类型和不同的精度进行比较,这可能会导致与您的情况一样的意外结果。

于 2013-05-18T18:59:50.913 回答
2

无法直接比较类型的floatdouble。在可以比较这些值之前,有必要将 转换doublefloat或将 转换floatdouble。如果进行前一种比较,转换将询问“是否保持' 值float的最佳float表示?” double如果进行后一种转换,问题将是“是否float完美表示double's 的值”。在许多情况下,前一个问题更有意义,但 Java 假定 和 之间的所有比较float都是double为了问后一个问题。

我建议无论一种语言愿意容忍什么,一个人的编码标准都应该绝对肯定地禁止直接比较 typefloatdouble. 给定如下代码:

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

d表示一个在float. 如果打算将f其转换为 a double,并且该转换的结果与 进行比较d,则应将比较写为

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

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

if ((float)d==f)

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

于 2013-12-20T22:41:56.137 回答
1

由于近似问题,通常将 == 运算符与浮点数一起使用并不是一个好习惯。

于 2013-05-18T18:58:41.277 回答
0

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 二进制:(11.001100110011001100110011001100110011001100110011001101...这里的精度很重要!)

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

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

基本上它与你用十进制数写 1/5 和 1/7 时相同:

1/5 = 0,2
1,7 = 0,14285714285714285714285714285714.
于 2015-08-07T09:20:30.940 回答
-1

Float 的精度低于 double,bcoz float 使用 32 位,其中 1 用于 Sign,23 精度和 8 用于 Exponent。其中 double 使用 64 位,其中 52 用于精度,11 用于指数,1 用于符号......精度是重要的问题。表示为浮点数和双精度的十进制数可以相等或不等取决于需要精度(即范围小数点后的数字可能会有所不同)。问候 S. ZAKIR

于 2015-08-07T11:59:16.103 回答