比较Java中的float和double原语

我遇到了一个奇怪的Java角落。(这对我来说似乎很奇怪)

double dd = 3.5; float ff = 3.5f; System.out.println(dd==ff); 

o / p:是的

 double dd = 3.2; float ff = 3.2f; System.out.println(dd==ff); 

o / p:false

我观察到,如果我们比较任何两个值(如我在示例中提到的float和double)与.5 OR .0如3.5,234.5,645.0,则输出为true即两个值相等,否则输出为false尽管它们是等于。

即使我试图制作方法strictfp但没有运气。 我错过了什么。

看看每个计算机科学家应该知道的关于浮点数的内容 。

将无限多个实数压缩成有限数量的位需要近似表示….

—编辑显示上述报价的含义—

你不应该比较浮动或双打的平等; 因为,你无法保证你赋予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 ... } 

不同之处在于3.5可以在floatdouble 精确表示 – 而3.2无法在两种类型中精确表示……并且两个最接近的近似值是不同的。

想象一下,我们有两个固定精度的十进制类型,其中一个存储4位有效数字,其中一个存储8位有效数字,我们要求每个存储最接近“三分之一”的数字(但我们可能会这样做)。 然后一个人的值为0.3333,一个人的值为0.33333333。

floatdouble之间的相等比较首先将float转换为double ,然后比较两者 – 这相当于将我们的“小十进制”类型中的0.3333转换为0.33330000。 然后它会比较0.33330000和0.33333333的相等性,并给出错误的结果。

浮点数的通用实现IEEE754允许仅精确表示具有短的有限二进制扩展的数 ,即有限多个(附近)2的幂的和。 所有其他数字无法准确表示。

由于floatdouble具有不同的大小,因此两种类型中对于不可表示的值的表示是不同的,因此它们比较为不相等。

(二进制字符串的长度是尾数的大小,因此float为24, double精度值为53,80位扩展精度浮点数为64(不是Java)。 比例由指数确定。)

浮点是二进制格式,它可以将数字表示为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(); 

这应该工作:

 BigDecimal ddBD = new BigDecimal(""+dd); BigDecimal ffBD = new BigDecimal(""+ff); // test for equality ddBO.equals(ffBD); 

当您想要比较浮点数或双精度数并始终使用BigDecimal构造函数和String参数时 ,始终使用BigDecimal!