这个答案的重点是解释为什么选择Math.min
完全可交换的语言设计是有意义的。
我很想知道为什么 -0 < 0 会发生?
它不是真的;<
是与“最小值”分开的操作,并且Math.min
不仅仅基于 IEEE<
比较,例如b<a ? b : a
.
那将是不可交换的。NaN 以及有符号零。(<
如果任一操作数为 NaN,则为假,因此会产生a
)。就最小惊讶原则而言,如果 is but
is 至少会令人惊讶(如果不是更多的话Math.min(-1,NaN)
)。NaN
Math.min(NaN, -1)
-1
JS 语言的设计者想要Math.min
成为 NaN 传播,所以仅仅基于它<
是不可能的。 他们选择使其完全可交换,包括有符号零,这似乎是一个明智的决定。
OTOH,大多数代码都不关心有符号零,因此这种语言设计选择会为每个人花费一些性能,以迎合某些人想要定义良好的有符号零语义的罕见情况。
如果您想要一个忽略数组中 NaN 的简单操作,请使用current_min = x < current_min ? x : current_min
. 这将忽略所有 NaN,也忽略-0
(current_min <= +0.0
IEEE 比较)。或者如果current_min
开始是 NaN,它将保持 NaN。其中许多事情对于Math.min
函数来说是不可取的,所以它不能那样工作。
如果你比较其他语言,C 标准fmin
函数是可交换的。NaN(如果有,则返回非 NaN,与 JS 相反),但不需要是可交换的。签名为零。一些 C 实现选择像 JS for +-0.0 for fmin
/一样工作fmax
。
但是C++std::min
纯粹是根据操作定义的,<
所以它确实以这种方式工作。(它旨在通用地工作,包括像字符串这样的非数字类型;不像std::fmin
它没有任何特定于 FP 的规则。)请参阅在 x86 上提供无分支 FP min 和 max 的指令是什么?回复:x86 的minps
指令和 C++std::min
都是不可交换的。NaN 并签名为零。
IEEE 754<
不会为您提供不同 FP 编号的总顺序。Math.min
除了 NaN(例如,如果你用它和Math.max
.Math.max
输入数组。
Math.min
如果没有类似查看它返回哪个 arg 的东西,单独进行排序是不够的==
,但是对于有符号零和 NaN 来说,这会分解。