2016-02-13 76 views
2

考虑下面的代码输出的布尔是Java的浮点整数运算

A: false 
B: false 
C: true 

当我试图通过任何小于65不起作用减去V1 + V2的总和,就好像减法永远发生。如果我将原语切换到两倍,问题就解决了。这是为什么发生?

private static final float V1 = 1076712940; 
private static final float V2 = 1070770707; 

public static void main(final String[] args) { 
    final float y = V1 + V2;//2147483647 

    System.out.println("A: ((y - 64) - 1) == (y - 65) --> " 
         + (((y - 64) - 1) == (y - 65))); /* A */ 
    System.out.println("B: (y > y - 64) --> " + (y > y - 64)); /* B */ 
    System.out.println("C: (y > y - 65) --> " + (y > y - 65)); /* C */ 
} 
+4

你认为'float'具有多少精度?提示:尝试'System.out.println(Float.toHexString(V1));'和'System.out.println(Float.toHexString(V2));'''你可以使用'double'作为'y', ' V1'和'V2'(但是'double'也缺乏无限精度)。 –

回答

9

浮点在内存中由符号位,尾数和指数表示,它们本质上是二进制分数。许多十进制数不能完全表示为二进制分数。在指数或尾数中增加位可以提高精度。

我相信在你的情况下,你已经保存的浮点数和64的值之间的差异并不是一个足够大的变化来具有不同的浮点表示。但是,因为double在尾数和指数中有附加位,所以它可以更精确,并且精确地表示减法。

+1

简单地说:大量的0.00 ... 001 x 10^n的差异将变得越来越大。 –

+0

我将V1和V2切换为Float.MAX_VALUE 结果发生了变化 A:真 B:假 C:假 您对此有何看法? – Richard

+0

您可以使用'Math.ulp(f)'删除任何给定值的精确精确级别,以显示该值与下一个可表示值之间的最小差异。 +1 –

1

这扩大一点在prior answer

原始程序在评论中包含一个声明y是2147483647.它不是。由于浮点四舍五入,这是2147483648.该程序看起来在y,和可表示的数字包围它。 BigDecimal的toString在没有科学记数法的情况下做了精确的转换,对于这种情况更为明确。 BigDecimal还对有限长度小数展开的数字进行精确算术,包括所有有限浮点数和双数。

import java.math.BigDecimal; 

public class Test { 
    private static final float V1 = 1076712940; 
    private static final float V2 = 1070770707; 

    public static void main(String[] args) { 
    final float y = V1 + V2;// 2147483647 
    BigDecimal yBD = new BigDecimal(y); 
    System.out.println("y = " + yBD); 
    BigDecimal down = new BigDecimal(Math.nextDown(y)); 
    System.out.println("nextDown(y) = " + down + " diff = " + yBD.subtract(down)); 
    BigDecimal up = new BigDecimal(Math.nextUp(y)); 
    System.out.println("nextUp(y) = " + up + " diff = " + up.subtract(yBD)); 
    System.out.println(Float.MAX_VALUE + Float.MAX_VALUE); 
    } 

} 

输出:

y = 2147483648 
nextDown(y) = 2147483520 diff = 128 
nextUp(y) = 2147483904 diff = 256 
Infinity 

2147483648是二的幂,所以它下面的间隙只有128,但上述的间隙是256减去任何小于64具有精确的结果更接近2147483648比任何其他可表示的数字。减去64会得出两个数字中间的精确结果,并且可以向2147483648舍入。减去65得到的结果更接近2147483520.

在评论中,您问:“我将V1V2Float.MAX_VALUE结果变了A:真B:假C:假你对此有何看法?

我的第一个想法,从我的程序的最后输出得到证实,是“这使得y无限。”。从无穷大增加或减少有限数字不会改变其值。无限等于自身。

一般来说,如果直接查看所涉及的数字,可以更容易地看到发生了什么,而不仅仅是查看测试结果和涉及它们的比较。