为什么 Math.min() return -0 来自 [+0, 0, -0]
Why does Math.min() return -0 from [+0, 0, -0]
我知道 (-0 === 0) 结果是真的。我很好奇为什么会出现 -0 < 0?
当我在 Whosebug 执行上下文中 运行 这段代码时,它 returns 0
。
const arr = [+0, 0, -0];
console.log(Math.min(...arr));
但是当我 运行 在浏览器控制台中使用相同的代码时,它 returns -0
。这是为什么?我试图在 google 上搜索它,但没有找到任何有用的信息。这个问题可能对某些实际例子没有价值,我想了解JS如何计算它。
const arr = [+0, 0, -0];
console.log(Math.min(...arr)); // -0
这是Math.min
的特色菜,as specified:
21.3.2.25 Math.min ( ...args )
[...]
- For each element number of coerced, do
a. If number is NaN, return NaN.
b. If number is -0 and lowest is +0, set lowest to -0.
c. If number < lowest, set lowest to number.
- Return lowest.
请注意,在大多数情况下,+0 和 -0 被同等对待,在 ToString 转换中也是如此,因此 (-0).toString()
计算为 "0"
。您可以在浏览器控制台中观察到差异是浏览器的实现细节。
规范出奇地矛盾。 <
比较规则明确表示 -0
不小于 +0
。然而,Math.min()
的规范说的恰恰相反:如果当前(在遍历参数时)值为 -0
,并且到目前为止的最小值是 +0
,那么最小值应该设置为 -0
.
我希望有人能激活 T.J。这个的克劳德信号。
edit — 在一些评论中有人建议这种行为的一个可能原因是可以检测到 -0
值,即使对于几乎所有在普通表达式中,-0
被视为普通表达式 0
.
-0
不小于0
或+0
,-0 < 0
和-0 < +0
returnsFalse
,你'将 Math.min
的行为与 -0
与 0
/+0
的比较相混合。
specification of Math.min
在这一点上很清楚:
b. If number is -0 and lowest is +0, set lowest to -0.
如果没有这个例外,Math.min
和 Math.max
的行为将取决于参数的顺序,这可以被认为是一种奇怪的行为——你可能希望 Math.min(x, y)
总是等于Math.min(y, x)
— 所以这可能是一个可能的理由。
注意:此异常已存在于 1997 specification 中 Math.min(x, y)
,因此这不是后来添加的内容。
这个答案的重点是解释为什么 Math.min
完全可交换的语言设计选择是有意义的。
I am curious to know why -0 < 0 happens?
不是真的; <
是与“最小值”分开的操作,并且 Math.min
不像 b<a ? b : a
.
那样仅基于 IEEE <
比较
那将是不可交换的。 NaN 以及符号零。 (如果任一操作数为 NaN,则 <
为假,因此会产生 a
)。
就最小惊喜原则而言,如果 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 standard fmin
function 是可交换的。 NaN(returning 非 NaN,如果有的话,与 JS 相反),但不需要是可交换的。签名为零。对于 fmin
/ fmax
.
的 +-0.0,一些 C 实现选择像 JS 一样工作
但是 C++ std::min
is defined purely in terms of a <
operation, so it does work that way. (It's intended to work generically, including on non-numeric types like strings; unlike std::fmin
it doesn't have any FP-specific rules.) See 回复:x86 的 minps
指令和 C++ std::min
都是不可交换的。 NaN 和符号零。
IEEE 754 <
不会为您提供不同 FP 编号的总顺序。 Math.min
除了 NaN(例如,如果你用它和 Math.max
构建了一个排序网络)它的顺序与 Math.max
不一致:它们都是 return NaN 如果有的话,因此使用 min/max 比较器的排序网络将生成所有 NaN,如果输入数组中有的话。
Math.min
如果没有 ==
之类的东西来查看它 return 编辑了哪个参数,单独使用
Math.min
是不够的,但是对于带符号的零和 NaN 来说,这会分解。
我知道 (-0 === 0) 结果是真的。我很好奇为什么会出现 -0 < 0?
当我在 Whosebug 执行上下文中 运行 这段代码时,它 returns 0
。
const arr = [+0, 0, -0];
console.log(Math.min(...arr));
但是当我 运行 在浏览器控制台中使用相同的代码时,它 returns -0
。这是为什么?我试图在 google 上搜索它,但没有找到任何有用的信息。这个问题可能对某些实际例子没有价值,我想了解JS如何计算它。
const arr = [+0, 0, -0];
console.log(Math.min(...arr)); // -0
这是Math.min
的特色菜,as specified:
21.3.2.25 Math.min ( ...args )
[...]
- For each element number of coerced, do
a. If number is NaN, return NaN.
b. If number is -0 and lowest is +0, set lowest to -0.
c. If number < lowest, set lowest to number.
- Return lowest.
请注意,在大多数情况下,+0 和 -0 被同等对待,在 ToString 转换中也是如此,因此 (-0).toString()
计算为 "0"
。您可以在浏览器控制台中观察到差异是浏览器的实现细节。
规范出奇地矛盾。 <
比较规则明确表示 -0
不小于 +0
。然而,Math.min()
的规范说的恰恰相反:如果当前(在遍历参数时)值为 -0
,并且到目前为止的最小值是 +0
,那么最小值应该设置为 -0
.
我希望有人能激活 T.J。这个的克劳德信号。
edit — 在一些评论中有人建议这种行为的一个可能原因是可以检测到 -0
值,即使对于几乎所有在普通表达式中,-0
被视为普通表达式 0
.
-0
不小于0
或+0
,-0 < 0
和-0 < +0
returnsFalse
,你'将 Math.min
的行为与 -0
与 0
/+0
的比较相混合。
specification of Math.min
在这一点上很清楚:
b. If number is -0 and lowest is +0, set lowest to -0.
如果没有这个例外,Math.min
和 Math.max
的行为将取决于参数的顺序,这可以被认为是一种奇怪的行为——你可能希望 Math.min(x, y)
总是等于Math.min(y, x)
— 所以这可能是一个可能的理由。
注意:此异常已存在于 1997 specification 中 Math.min(x, y)
,因此这不是后来添加的内容。
这个答案的重点是解释为什么 Math.min
完全可交换的语言设计选择是有意义的。
I am curious to know why -0 < 0 happens?
不是真的; <
是与“最小值”分开的操作,并且 Math.min
不像 b<a ? b : a
.
<
比较
那将是不可交换的。 NaN 以及符号零。 (如果任一操作数为 NaN,则 <
为假,因此会产生 a
)。
就最小惊喜原则而言,如果 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 standard fmin
function 是可交换的。 NaN(returning 非 NaN,如果有的话,与 JS 相反),但不需要是可交换的。签名为零。对于 fmin
/ fmax
.
但是 C++ std::min
is defined purely in terms of a <
operation, so it does work that way. (It's intended to work generically, including on non-numeric types like strings; unlike std::fmin
it doesn't have any FP-specific rules.) See minps
指令和 C++ std::min
都是不可交换的。 NaN 和符号零。
IEEE 754 <
不会为您提供不同 FP 编号的总顺序。 Math.min
除了 NaN(例如,如果你用它和 Math.max
构建了一个排序网络)它的顺序与 Math.max
不一致:它们都是 return NaN 如果有的话,因此使用 min/max 比较器的排序网络将生成所有 NaN,如果输入数组中有的话。
Math.min
如果没有 ==
之类的东西来查看它 return 编辑了哪个参数,单独使用
Math.min
是不够的,但是对于带符号的零和 NaN 来说,这会分解。