鉴于下面的代码,输出的布尔值是
A: false
B: false
C: true
当我尝试用小于65的任何东西减去V1 + V2的总和时,它就好像从不发生减法一样。如果我将原语切换为double,问题就解决了。为什么会这样?
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 */
}
答案 0 :(得分:9)
浮点数由符号位,尾数和指数表示在内存中,它们基本上是二进制分数。许多十进制数不能完全表示为二进制分数。在指数或尾数中具有附加位将允许更高的精度水平。
我相信在你的情况下,你保存的浮点数与64减去的值之间的差异不是一个足够大的变化,以具有不同的浮点表示。但是,因为double在尾数和指数中有额外的位,所以它可以更精确,并准确地表示减法。
答案 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是2的幂,所以它下面的间隙只有128,但是上面的间隙是256.减去任何小于64的东西的确切结果接近2147483648而不是任何其他可表示的数字。减去64给出了两个数字之间的精确结果,以及向2147483648的四舍五入到第八轮。减去65具有更接近2147483520的精确结果。
在评论中,您会问:“我已将V1
和V2
切换为Float.MAX_VALUE
结果已更改A:true B:false C:false您对此有何看法? ?“
我的第一个想法是,通过我的程序的最后一个输出证实,“这使得y
无限。”在无穷大中添加或减去有限数不会改变其值。无穷大等于它自己。
一般来说,如果你直接查看所涉及的数字,而不是仅仅查看测试结果和涉及它们的比较,就会更容易看到发生了什么。