我正在比较Double
和float
值的代码中工作:
class Demo {
public static void main(String[] args) {
System.out.println(2.0 - 1.1);
System.out.println(2.0 - 1.1 == 0.9);
System.out.println(2.0F - 1.1F);
System.out.println(2.0F - 1.1F == 0.9F);
System.out.println(2.0F - 1.1F == 0.9);
}
}
输出如下:
0.8999999999999999
false
0.9
true
false
我相信Double
值比float
可以节省更多的精度。
[请说明这一点,看起来float
值不是丢失精度,而是double
一个丢失?
编辑:@goodvibration我知道0.9不能以任何计算机语言完全保存,我只是很困惑java如何详细地使用它,为什么2.0F - 1.1F == 0.9F
,但是2.0 - 1.1 != 0.9
,另一个有趣的发现可能会有所帮助:
class Demo {
public static void main(String[] args) {
System.out.println(2.0 - 0.9); // 1.1
System.out.println(2.0 - 0.9 == 1.1); // true
System.out.println(2.0F - 0.9F); // 1.1
System.out.println(2.0F - 0.9F == 1.1F); // true
System.out.println(2.0F - 0.9F == 1.1); // false
}
}
我知道我不能指望浮点数或双精度,只是..无法弄清楚这让我发疯了,这背后的真正目的是什么?为什么2.0 - 0.9 == 1.1
但2.0 - 1.1 != 0.9
??
弹出测验:以小数表示1/3。
答案:您不能;不完全是。
计算机以二进制计数。还有更多数字“无法完全代表”。就像在十进制问题中,如果只有一小块纸可以写,您可以简单地用0.3333333
命名为一天,然后得到一个非常接近的数字,但与1 / 3
并不完全相同,计算机也代表分数。
或者,这样考虑:浮点数占用32位;双占64位。32位值只能表示2 ^ 32(约40亿)个不同的数字。但是,即使在0到1之间,也有无限数量的数字。因此,鉴于最多有2 ^ 32个具体的具体数字可以“精确地”表示为浮点数,因此,在约40亿个值的受祝福集合中没有的任何数字都无法表示。您可以从这个40亿个可表示的值池中获得一个值,而不是仅仅出错,它是最接近您想要的值。]
此外,由于计算机以二进制而不是十进制计数,因此您对“可表示”和“不可以表示”的感觉已经关闭。您可能会认为1/3是个大问题,但肯定1/10很容易,对吧?就是0.1
,这是一个精确的表示。啊,但是十分之一在十进制中效果很好。毕竟,十进制是基于数字10的,这并不奇怪。但是用二进制?一半,四分之一,八分之一,十六分之一:二进制容易。十分之一?这和第三个难度一样:NOT REPRESENTABLE
0.9本身不是可表示的数字。但是,当您打印浮标时,就是这样。
原因是,打印浮点数/双打是一门艺术,而不是一门科学。假设只有少数数字是可表示的,并且由于二进制v。十进制的原因,这些数字对人类而言并不“自然”,那么您确实需要在数字上添加“取整”策略,否则看起来疯狂(没人想读0.899999999999999999765)。这正是System.out.println及其合作伙伴所做的。
但是您实际上应该控制舍入功能:切勿使用System.out.println打印双精度和浮点型。请改用System.out.printf("%.6f", yourDouble);
,在这种情况下,两者都将打印0.9
。因为虽然两者都不能真正精确地表示0.9,但最接近浮点数的数字(或者更确切地说,就是取最接近2.0的数字(即2.0)和最接近1.1的数字(不是精确地1.1)),减去它们,然后找到最接近该结果的数字)–即使不是浮点数也打印为0.9,并且不打印为0.9的两倍。
float
和double
之间的差异: