我遇到了Java的一个奇怪的角落。(这对我来说似乎很奇怪)
double dd = 3.5;
float ff = 3.5f;
System.out.println(dd==ff);
o / p:true
double dd = 3.2;
float ff = 3.2f;
System.out.println(dd==ff);
o / p:false
我观察到,如果我们将.5
或.0
的任何两个值(浮点数和双精度数)与3.5,234.5,645.0进行比较
然后输出为true
,即两个值相等,否则输出为false
,尽管它们是等于。
即使我尝试制作方法strictfp
但没有运气。
我错过了什么。
答案 0 :(得分:20)
看看What every computer scientist should know about floating point numbers。
将无限多个实数压缩成有限数量的位需要近似表示....
---编辑以显示上述报价的含义---
你不应该比较浮动或双打的平等;因为,你无法保证你指定给float或double的数字是准确的。
所以
float x = 3.2f;
不会导致值为3.2的浮点数。它导致浮点值为3.2加上或减去一些非常小的误差。说3.19999999997f。现在很明显为什么比较不起作用。
为了比较浮动的平等性,您需要检查该值是否“足够接近”到相同的值,如此
float error = 0.000001 * second;
if ((first >= second - error) || (first <= second + error)) {
// close enough that we'll consider the two equal
...
}
答案 1 :(得分:10)
不同之处在于,float
和double
中的3.5可以完全表示为 ,而3.2无法在两种类型中完全表示......最接近的近似值不同。
想象一下,我们有两个固定精度十进制类型,其中一个存储了4位有效数字,其中一个存储了8位有效数字,我们要求他们每个存储最接近“a”的数字第三个“(但我们可能会这样做)。然后一个人的值为0.3333,一个人的值为0.33333333。
float
和double
之间的平等比较首先将float
转换为double
,然后比较两者 - 这相当于在我们的“小”中转换0.3333十进制“类型为0.33330000。然后它会比较0.33330000和0.33333333的相等性,并给出错误的结果。
答案 2 :(得分:3)
浮点数的通用实现IEEE754允许精确表示那些具有短,有限二进制扩展的数字,即有限多个(附近)幂的总和两个。所有其他数字无法准确表示。
由于float
和double
具有不同的大小,因此两种类型中不可表示的值的表示方式不同,因此它们的比较为不相等。
(二进制字符串的长度是尾数的大小,因此float
为24,double
为53,80位扩展为64精度浮点数(不是Java)。 scale 由指数决定。)
答案 3 :(得分:3)
浮点是二进制格式,它可以将数字表示为2的幂之和。 3.5是2 + 1 + 1/2。
float 3.2f作为3.2的近似值
2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/4194304 + a small error
然而,作为3.2的近似值的双倍3.2d是
2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/8388608+ 1/16777216+ 1/134217728+ 1/268435456+ 1/2147483648+ 1/4294967296+ 1/34359738368+ 1/68719476736+ 1/549755813888+ 1/1099511627776+ 1/8796093022208+ 1/17592186044416+ 1/140737488355328+ 1/281474976710656+ 1/1125899906842624 + a smaller error
使用浮点时,需要使用适当的舍入。如果你使用BigDecimal(很多人都这样做),它内置了舍入。
double dd = 3.2;
float ff = 3.2f;
// compare the difference with the accuracy of float.
System.out.println(Math.abs(dd - ff) < 1e-7 * Math.abs(ff));
BTW用于打印分数为double的代码。
double f = 3.2d;
double f2 = f - 3;
System.out.print("2+ 1");
for (long i = 2; i < 1L << 54; i <<= 1) {
f2 *= 2;
if (f2 >= 1) {
System.out.print("+ 1/" + i);
f2 -= 1;
}
}
System.out.println();
答案 4 :(得分:0)
这应该有效:
BigDecimal ddBD = new BigDecimal(""+dd);
BigDecimal ffBD = new BigDecimal(""+ff);
// test for equality
ddBO.equals(ffBD);
如果要比较浮点数或双精度数,请始终使用 BigDecimal 并始终使用BigDecimal构造函数和 String参数!