您的表达式将可靠地产生以下结果false
在爪哇。
然而,假设零是 -1 除以正无穷大的结果。在这种情况下,粗略地说,它将在内部表示为 -0.00。在某些情况下,它仍会被打印为零(不带减号),而在其他情况下,它的表现将与 0.00 不同。
通常可以按照与整数相同的方式比较浮点数是否小于 - 存在舍入误差的风险,但通过添加或减去随机小值并不能解决该错误。这与平等比较不同。
我建议你仔细检查你的事实并多读书 http://www.concentric.net/~ttwang/tech/javafloat.htm关于浮点行为。
Edit:我在上面大大简化了回答原来的问题。要回答对问题的编辑,我们需要更深入。
For 任何操作关于浮点数,人们应该了解并考虑精确 and accuracy输入的数量,以及期望的准确度的输出。有时任务是可以解决的,有时却不是——输入的准确性可能不足以产生答案。
就你而言,精确是32位,其中24位是尾数,8位指数。这意味着该数据类型可以安全地区分 0.001 和 0.00100001,但不能区分 0.001000001,如您所见:
System.out.println((float)0.001 < (float)0.001000001);
(请注意,如果您不通过强制转换强制进行单精度比较,您将得到不同的结果。在这种情况下,计算将以双精度完成,并且数字将被安全地区分 - 直到您将它们拉得更近。)
因此,精度由数据类型决定。不太准确。输入精度通常比精度更难确定,因为它与数据类型无关,只是精度永远不会比精度更好。
就特定浮点类型的可表示性而言,数学实数可能处于四种可能的情况下,这些情况对应于当它以人类可读的十进制表示法作为文字出现时所接受的不同处理。
- 它可以用二进制准确地表示。例如,0 或 0.25。那么它就和整数变量中的整数一样准确。
- 或者它可以用与类型的精度相对应的精度来近似表示。例如,1/3 或 0.1 或 0.001。当所需的指数适合可用的指数位数,但当数字的二进制扩展比尾数长或完全无限时,就会发生这种情况。
- 或者它可以近似地表示,但精度却严重扭曲。这些都是denormal http://en.wikipedia.org/wiki/Denormal_number(次正规)数字。它不仅不准确,而且它的算术运算可能会慢得像爬行一样,这通常是记录在案的正确行为,甚至一个受人尊敬的 Java 编译器在看到这种类型的文字时也会有点出汗,但这是一个bug http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/.
- 或者它根本不适合,编译器会因为太大而拒绝该文字。
因此,在您的情况下,我们只有三个有效输入:0(准确)、0.001(近似)和-0.001(近似),这使得您的问题可以解决。只需将您的数字与 0 文字进行比较(顺便说一下,这是准确的)和你总是会得到预期的布尔值(完全准确的输出)。
然而,这取决于您的输入是直接从文字派生的。如果您的输入是 0.001、-0.001 和之一(float)1000 * (float)0.001 - 1
,这将是一个不同的问题,您必须得到答案,例如这样:
if (-0.00001 < x && x < 0.00001) // then x is zero
如果您允许任何输入,而不仅仅是这三个神奇值,并且不知道输入的准确性,那么这就是不可能完成的任务。即使是字面意思开头的0.000000000...
最后的一些垃圾数字将被 Java 编译器转换为完全中性的零,发生这种情况后,再多的 Java 代码也无法区分它与准确而漂亮的数字0.00
,或者如果在下溢值上添加减号会发生什么。都是一样的,不准确的零,变量中的位模式相同,而不是 3 个不同的值。