此方法返回'true'。为什么?
public static boolean f() {
double val = Double.MAX_VALUE/10;
double save = val;
for (int i = 1; i < 1000; i++) {
val -= i;
}
return (val == save);
}
答案 0 :(得分:25)
您从巨大值中减去相当小的值(小于1000)。小值远小于理论结果的最接近可表示值仍然是原始值的大值。
基本上它是浮点数运算方式的结果。
想象一下,我们有一些十进制浮点类型(仅为了简单起见),它只在尾数中存储了5位有效数字,并且在0到1000范围内存储了一个指数。
你的例子就像写10 999 - 1000 ...当四舍五入到5位有效数字时,想想结果会是什么。是的,完全结果是99999 ..... 9000(有999位数字)但是如果你只能用5位有效数字表示值,那么最接近的结果是10 999 试。
答案 1 :(得分:2)
将val
设置为Double.MAX_VALUE / 10时,会将其设置为大约等于1.7976931348623158 * 10^307
的值。从那里减去像1000那样的值就需要双重表示的精度是不可能的,所以它基本上保持val
不变。
根据您的需要,您可以使用BigDecimal
代替double
。
答案 2 :(得分:2)
Double.MAX_VALUE
非常大,以至于JVM没有区分它和Double.MAX_VALUE-1000
如果从Double.MAV_VALUE
中减去少于“1.9958403095347198E292”的数字,结果仍为Double.MAX_VALUE
。
System.out.println(
new BigDecimal(Double.MAX_VALUE).equals( new BigDecimal(
Double.MAX_VALUE - 2.E291) )
);
System.out.println(
new BigDecimal(Double.MAX_VALUE).equals( new BigDecimal(
Double.MAX_VALUE - 2.E292) )
);
Ouptup:
真
假
答案 3 :(得分:1)
double没有足够的精度来执行您尝试的计算。因此结果与初始值相同。
与==
运算符无关。
答案 4 :(得分:1)
val
是一个很大的数字,当从中减去1
(或甚至1000
)时,结果无法正确表示为double
值。此数字x
和x-1
的表示形式相同,因为double
只有有限的位数来表示无限数量的数字。
答案 5 :(得分:1)
Double.MAX_VALUE
与1或1000相比是一个巨大的数字。Double.MAX_VALUE-1
通常等于Double.MAX_VALUE
。因此,当将1或1000减去Double.MAX_VALUE/10
时,您的代码大致无效。
永远记住:
double
s或float
s只是实数的近似值,它们只是在实数中不均匀分配的有理数double
或float
s之间使用非常仔细的算术运算符,这些运算符不是很接近(还有许多其他规则,比如这样......)double
或float
答案 6 :(得分:0)
因为double
是floating point数字类型,这是近似数值的一种方式。浮点表示对数字进行编码,以便我们可以存储比通常情况更大或更小的数字。但是,并非所有数字都可以在给定空间中表示,因此多个数字将四舍五入为相同的浮点值。
作为一个简化示例,我们可能希望能够在一些少量空间中存储-1000到1000之间的值,而我们通常只能存储-10到10.因此我们可以将所有值都舍入到最近的千位并将它们存储在小空间中:-1000编码为-10
,-900编码为-9
,1000编码为10
。但是如果我们要存储-999怎么办?我们可以编码的最接近的值是-1000,因此我们必须将-999编码为与-1000相同的值:-10
。
实际上,浮点方案比上面的例子复杂得多,但概念类似。数字的浮点表示只能表示所有可能数字的某些,所以当我们有一个无法表示为方案一部分的数字时,我们必须将其四舍五入到最接近的可表示值
在您的代码中,Double.MAX_VALUE / 10
的1000个内的所有值都会自动舍入为Double.MAX_VALUE / 10
,这就是计算机认为(Double.MAX_VALUE / 10) - 1000 == Double.MAX_VALUE / 10
的原因。
答案 7 :(得分:0)
浮点计算的结果是与确切答案最接近的可表示值。这个计划:
public class Test {
public static void main(String[] args) throws Exception {
double val = Double.MAX_VALUE/10;
System.out.println(val);
System.out.println(Math.nextAfter(val, 0));
}
}
打印:
1.7976931348623158E307
1.7976931348623155E307
这些数字中的第一个是你原来的val。第二个是最小的双倍,小于它。
当你从1.7976931348623158E307中减去1000时,确切的答案是在这两个数字之间,但非常非常接近1.7976931348623158E307而不是1.7976931348623155E307,所以结果将四舍五入为1.7976931348623155E307,保持val不变。