我查看了java.lang.Math
源代码中的一些东西,我注意到虽然Math.min(int, int)
(或它的长对应项)是这样实现的:
public static int min(int a, int b) {
return a <= b ? a : b;
}
这对我来说是完全有意义的,这和我会做的是一样的。然而,double/float实现是这样的:
public static float min(float a, float b) {
if (a != a) {
return a;
} else if (a == 0.0F && b == 0.0F && (long)Float.floatToRawIntBits(b) == negativeZeroFloatBits) {
return b;
} else {
return a <= b ? a : b;
}
}
我完全被吓呆了。将a
与自身进行比较?第二次检查到底是为了什么?为什么它不以与int/long版本相同的方式实现?
发布于 2021-05-06 08:01:13
Floating-point数比整数值复杂得多。
对于这种特定情况,有两个区别很重要:
NaN
是float
和double
的有效值,表示“不是数字”,行为怪异。也就是说,它不等于itself.所以这一部分:
if (a != a) {
return a;
}
确保如果a
为NaN
,则返回NaN
(如果a
不是NaN
,但b
是,则稍后的“正常”检查将返回b
,即NaN
,因此这种情况不需要显式检查)。这是一种常见的模式:在计算输入为NaN
的任何内容时,输出也将为NaN
。
这部分:
if (a == 0.0F && b == 0.0F && (long)Float.floatToRawIntBits(b) == negativeZeroFloatBits) {
return b;
}
与NaN
类似,如果正常检查为-0.0且b
为0.0,则正常检查将正确返回a
。
发布于 2021-05-06 08:04:21
我建议仔细阅读Math.min
的文档以及关于浮点的numeric comparison operators。他们的行为是完全不同的。
来自Math.min
的相关部分
根据IEEE754标准的规范确定的浮点比较结果为:
如果任何参数为NaN,Math.min
将选取该参数,但如果任何操作数为NaN,则<=
的计算结果为false
。这就是为什么它必须检查a
是否与自身不相等-这意味着a
是NaN。
这就是第二次检查的目的。
发布于 2021-05-06 08:14:38
我可以在第一个比较if (a != a)
上帮你。这显然只考虑了a
,所以在哪些情况下,无论b
如何,a
都可能是最小的
float
数字与int
的不同之处在于它有special values,例如NAN
。NAN
的一个特殊属性是比较总是假的。因此,如果a
上的每个比较运算符都返回false,则第一个条件返回a
。
在最后一行中可以找到与b
相同的条件。如果b
上的比较总是返回false,那么最后一行总是返回b
。
在第二种情况下,我只能猜测这与“负零”和“正零”有关,这是float
的另外两个特殊值。当然,负零比正零小。
https://stackoverflow.com/questions/67414007
复制