2

我正在使用 jdk 1.6。这是我的代码。

float f = 10.0f;

double d = 10.0; 

System.out.println("Equal Status : " + (f == d)); 

然后系统将答案显示为true。但是如果我将值修改为

float f = 10.1f; 

double d = 10.1; 

System.out.println("Equal Status : " + (f == d));

然后系统将答案显示为错误。我知道系统使用位匹配进行 == 检查。但背后的原因是什么。你能解释一下吗?提前致谢。

4

7 回答 7

1

虽然这不是“我的”答案,但对于想要从“meh”转变为“good”的程序员来说,这几乎是“必须阅读”的文献。伟大是真正特别的东西,所以不要认为“好”是什么可以打喷嚏的。:)

每个程序员都需要了解的浮点知识

于 2012-07-12T03:31:47.050 回答
1

恕我直言,一般来说,99% 的用例double是更好的选择,因为它更准确。float即除非必须,否则不要使用。

BigDecimal 可用于显示 afloat或的实际表示double。您通常不会看到这一点,因为toString它将执行少量舍入(因为它被编码以适应类型表示限制)

System.out.println("10.1f is actually " + new BigDecimal(10.1f));
System.out.println("10.1 is actually " + new BigDecimal(10.1));

印刷

10.1f is actually 10.1000003814697265625
10.1 is actually 10.0999999999999996447286321199499070644378662109375

您可以看到该double值更接近所需的 10.1,但不完全是这个值。值不同的原因是,在每种情况下,它都具有该类型最接近的可替换值。

于 2012-07-12T06:52:54.047 回答
1

要记住的要点是

  1. 10.1是二进制1010101010的重复序列……
  2. 当比较浮点数和双精度浮点数时,通过添加零来填充数字,将浮点数转换为双精度数

    所以你会比较

    1010101...00000000... 到 1010101.....101010... 这是不同的。

    浮动 f = 10.1f;

    双 d = 10.1;

    System.out.println("相等状态:" + (f == (float)d));

会给出真实的答案

于 2012-07-12T04:59:48.250 回答
1

@Sam 建议的链接很棒,但对我来说仍然太技术性:P

我将就处理浮点数向 OP 提出一些意见(可能有点离题,因为您在询问背后的原因。对于背后的原因,请阅读链接@Sam 建议)。

永远不要假设浮点数会给你准确的表示。有时可以,但并非总是如此。浮点数在“有效数字”中有其约束,对于第一个第 n 位它是“准确的”。

你的情况更糟,因为你混合了浮点数和双精度数,但解决的想法是相似的。

您需要确定您的应用程序需要计算结果的精度,并据此确定 Epsilon 值。例如,您的应用程序只需要精确到小数点后 3 位,可能 Epsilon 为 0.0005 是合理的。

比较两个浮点数不应该由==. 你应该使用 (a + EPSILON > b && a - EPSILON < b). 同样,a > b应表示为a - EPSILON > b

于 2012-07-12T04:02:08.830 回答
0

float是 32 位类型,而double是 64 位类型。

您遇到了经典的浮点精度问题。

于 2012-07-12T03:27:58.360 回答
0

浮点数不精确。由于四舍五入,10.1f 和 10.1 的实际值会略有不同。浮点数是二进制的,而不是十进制的,所以对我们来说看起来“简单”的数字,比如 10.1,不能完全表示为浮点数。

于 2012-07-12T03:28:17.267 回答
0

您可能希望重新了解 32 位和 64 位浮点表示的IEEE 浮点标准。如果您深入了解它的内部结构,您会清楚地看到为什么这些浮点会表现得如此挑剔。

如果您对它在内部的表示方式感到好奇(这就是它失败的原因),您可以使用这段代码,它显示了这些数字的十六进制表示。从那里,您可以将它们与单精度和双精度的指数和尾数相匹配。

System.out.printf("Float 10.0: 0x%X\n", Float.floatToRawIntBits((float)10.0));
System.out.printf("Double 10.0: 0x%X\n", Double.doubleToRawLongBits(10.0));
System.out.printf("Float 10.1: 0x%X\n", Float.floatToRawIntBits((float)10.1));
System.out.printf("Double 10.1: 0x%X\n", Double.doubleToRawLongBits(10.1));

印刷

Float 10.0: 0x41200000
Double 10.0: 0x4024000000000000
Float 10.1: 0x4121999A
Double 10.1: 0x4024333333333333

您会注意到值的表示方式存在一些重复。这是因为 1/10不能在以 2 为底的有限空间中表示

于 2012-07-12T04:11:07.650 回答