JavaScript 中的 Number.sign()
想知道是否有任何重要的方法可以找到数字的符号(符号函数)?
可能比显而易见的
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
简短答案更短/更快/更优雅的解决方案!
使用这个,你会安全又快速(来源:moz)
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
您可能想查看性能和类型强制比较fiddle
已经过去很长时间了。进一步主要是历史原因。
结果
目前我们有以下解决方案:
1. 明显且快速
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. 修改自 kbec -一种类型转换更少,性能更高,更短[最快]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
注意: sign("0") -> 1
2. 优雅,简短,不太快[最慢]
function sign(x) { return x && x / Math.abs(x); }
注意: sign(+-Infinity) - > NaN
, sign("0") ->; NaN
由于 Infinity 是 JS 中的合法数字,因此该解决方案似乎并不完全正确。
3. 艺术......但非常慢[最慢]
function sign(x) { return (x > 0) - (x < 0); }
4. 使用位移位
快,但是sign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. 类型安全 [megafast]
! 看起来浏览器(尤其是 chrome 的 v8)发挥了一些作用优化,并且该解决方案比其他解决方案性能更高,甚至比 (1.1) 更高,尽管它包含 2 个额外的操作,并且从逻辑上讲永远不会更快。
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
工具
欢迎改进!
[Offtopic] 接受的答案
Andrey Tarantsov - +100 的艺术,但遗憾的是它比明显的方法慢了大约 5 倍
Frédéric Hamidi - 不知怎的,得到最多支持的答案(在撰写本文时),这有点酷,但这绝对不是事情应该如何完成,恕我直言。此外,它不能正确处理无穷大数字,这也是数字,你知道。
kbec - 是对显而易见的解决方案的改进。虽然不是那么革命性,但综合考虑,我认为这种方法是最好的。投票给他:)
Wonder if there are any nontrivial ways of finding number's sign (signum function)?
May be shorter / faster / more elegant solutions than the obvious one
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
Short answer!
Use this and you'll be safe and fast (source: moz)
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
You may want to look at performance and type-coercing comparison fiddle
Long time has passed. Further is mainly for historical reasons.
Results
For now we have these solutions:
1. Obvious and fast
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. Modification from kbec - one type cast less, more performant, shorter [fastest]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
caution: sign("0") -> 1
2. Elegant, short, not so fast [slowest]
function sign(x) { return x && x / Math.abs(x); }
caution: sign(+-Infinity) -> NaN
, sign("0") -> NaN
As of Infinity
is a legal number in JS this solution doesn't seem fully correct.
3. The art... but very slow [slowest]
function sign(x) { return (x > 0) - (x < 0); }
4. Using bit-shift
fast, but sign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Type-safe [megafast]
! Seems like browsers (especially chrome's v8) make some magic optimizations and this solution turns out to be much more performant than others, even than (1.1) despite it contains 2 extra operations and logically never can't be faster.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
Tools
Improvements are welcome!
[Offtopic] Accepted answer
Andrey Tarantsov - +100 for the art, but sadly it is about 5 times slower than the obvious approach
Frédéric Hamidi - somehow the most upvoted answer (for the time writing) and it's kinda cool, but it's definitely not how things should be done, imho. Also it doesn't correctly handle Infinity numbers, which are also numbers, you know.
kbec - is an improvement of the obvious solution. Not that revolutionary, but taking all together I consider this approach the best. Vote for him :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
更优雅的快速解决方案版本:
More elegant version of fast solution:
将数字除以其绝对值也可以得出其符号。使用短路逻辑 AND 运算符允许我们使用特殊情况
0
,这样我们就不会最终除以它:Dividing the number by its absolute value also gives its sign. Using the short-circuiting logical AND operator allows us to special-case
0
so we don't end up dividing by it:您正在寻找的函数称为 signum,实现它的最佳方法是:
The function you're looking for is called signum, and the best way to implement it is:
这应该不支持 JavaScript (ECMAScript) 的签名零吗?当在“megafast”函数中返回 x 而不是 0 时,它似乎可以工作:
这使得它与 ECMAScript 的 Math.sign (MDN):
Should this not support JavaScript’s (ECMAScript’s) signed zeroes? It seems to work when returning x rather than 0 in the “megafast” function:
This makes it compatible with a draft of ECMAScript’s Math.sign (MDN):
对于对最新浏览器的情况感兴趣的人,在 ES6 版本中,有一个原生的 Math.sign 方法。您可以在此处查看支持。
基本上它返回
-1
、1
、0
或NaN
For people who are interested what is going on with latest browsers, in ES6 version there is a native Math.sign method. You can check the support here.
Basically it returns
-1
,1
,0
orNaN
如果您不需要 Infinity 并且知道该数字是整数,则超级快,可在 openjdk-7 源代码中找到:
java.lang.Integer.signum()
Superfast if you do not need Infinity and know that the number is an integer, found in openjdk-7 source:
java.lang.Integer.signum()
我想我添加这个只是为了好玩:
0 和 NaN 将返回 -1
在 +/-Infinity 上工作正常
I thought I'd add this just for fun:
0 and NaN will return -1
works fine on +/-Infinity
适用于所有数字、
0
和-0
、以及Infinity
和-Infinity
的解决方案>,是:参见问题“+0 和 -0 相同吗?”了解更多信息。
警告:这些答案都不是,包括现在标准的
Math.sign
将适用于0
与-0
的情况。这对您来说可能不是问题,但在某些物理实现中可能很重要。A solution that works on all numbers, as well as
0
and-0
, as well asInfinity
and-Infinity
, is:See the question "Are +0 and -0 the same?" for more information.
Warning: None of these answers, including the now standard
Math.sign
will work on the case0
vs-0
. This may not be an issue for you, but in certain physics implementations it may matter.您可以对数字进行位移位并检查最高有效位 (MSB)。如果 MSB 为 1,则该数字为负数。如果为 0,则该数字为正数(或 0)。
You could bit shift the number and check the Most Significant Bit (MSB). If the MSB is a 1 then the number is negative. If it is 0 then the number is positive (or 0).
我正要问同样的问题,但在我写完之前就找到了解决方案,看到这个问题已经存在,但没有看到这个解决方案。
(n >> 31) + (n > 0)
通过添加三元似乎更快
(n >> 31) + (n> 0) 0?1:0)
I just was about to ask the same question, but came to a solution before i was finished writing, saw this Question already existed, but didn't saw this solution.
(n >> 31) + (n > 0)
it seems to be faster by adding a ternary though
(n >> 31) + (n>0?1:0)
与 Martijn 的答案非常相似的是
我发现它更具可读性。此外(或者,取决于您的观点),它还可以理解可以解释为数字的事物;例如,当出现
'-5'
时,它会返回-1
。Very similar to Martijn's answer is
I find it more readable. Also (or, depending on your point of view, however), it also groks things that can be interpreted as a number; e.g., it returns
-1
when presented with'-5'
.我没有看到从 Math.sign 返回 -0 和 0 的任何实际意义,所以我的版本是:
I don't see any practical sence of returning -0 and 0 from
Math.sign
so my version is:我知道的方法如下:
Math.sign(n)
var s = Math.sign(n)
这是本机函数,但速度最慢,因为函数调用的开销。然而,它确实处理“NaN”,而下面的其他内容可能只是假设 0(即 Math.sign('abc') 是 NaN)。
((n>0) - (n<0))
var s = ((n>0) - (n<0));
在这种情况下,只有左边或者根据符号右侧可以是 1。这会导致
1-0
(1)、0-1
(-1) 或0-0
(0)。这个速度似乎与 Chrome 中的下一个速度并驾齐驱。
(n>>31)|(!!n)
var s = (n>>31)|(!!n);
使用“符号传播右移”。基本上移位 31 会丢弃除符号之外的所有位。如果设置了符号,则结果为 -1,否则为 0。
|
的右侧通过将值转换为布尔值(0 或 1 [顺便说一句:非数字字符串,例如!!'abc'
,在本例中变为 0,而不是 NaN]),然后使用按位 OR 运算来组合这些位。这似乎是所有浏览器中最好的平均性能(至少在 Chrome 和 Firefox 中是最好的),但并不是所有浏览器中最快的。由于某种原因,三元运算符在 IE 中速度更快。
n?n<0?-1:1:0
var s = n?n<0?-1:1:0;
由于某种原因,在 IE 中最快。
jsPerf
执行的测试:https://jsperf.com/get-sign -来自值
The methods I know of are as follows:
Math.sign(n)
var s = Math.sign(n)
This is the native function, but is slowest of all because of the overhead of a function call. It does however handle 'NaN' where the others below may just assume 0 (i.e. Math.sign('abc') is NaN).
((n>0) - (n<0))
var s = ((n>0) - (n<0));
In this case only the left or right side can be a 1 based on the sign. This results in either
1-0
(1),0-1
(-1), or0-0
(0).The speed of this one seems neck and neck with the next one below in Chrome.
(n>>31)|(!!n)
var s = (n>>31)|(!!n);
Uses the "Sign-propagating right shift". Basically shifting by 31 drops all bits except the sign. If the sign was set, this results in -1, otherwise it is 0. Right of
|
it tests for positive by converting the value to boolean (0 or 1 [BTW: non-numeric strings, like!!'abc'
, become 0 in this case, and not NaN]) then uses a bitwise OR operation to combine the bits.This seems the best average performance across the browsers (best in Chrome and Firefox at least), but not the fastest in ALL of them. For some reason, the ternary operator is faster in IE.
n?n<0?-1:1:0
var s = n?n<0?-1:1:0;
Fastest in IE for some reason.
jsPerf
Tests performed: https://jsperf.com/get-sign-from-value
我的两分钱,有一个返回与 Math.sign 相同结果的函数,即 sign(-0) --> -0, 符号(-无穷大) --> -无穷大,符号(null) --> 0, 符号(未定义) --> NaN 等。Jsperf
不允许我创建测试或修订,很抱歉无法为您提供测试(我已经尝试过 jsbench.github.io,但结果似乎比 Jsperf 更接近) ...)
如果有人可以将其添加到 Jsperf 修订版中,我很好奇它与之前给出的所有解决方案相比如何...
谢谢!
吉姆.
编辑:
我应该写:(
(+x && -1)
而不是(x && -1)
) 以便正确处理sign('abc')
(--> NaN)My two cents, with a function that returns the same results as Math.sign would do, ie sign(-0) --> -0, sign(-Infinity) --> -Infinity, sign(null) --> 0, sign(undefined) --> NaN, etc.
Jsperf won't let me create a test or revision, sorry for not being able to provide you with tests (i've given jsbench.github.io a try, but results seem much closer to one another than with Jsperf...)
If someone could please add it to a Jsperf revision, I would be curious to see how it compares to all the previously given solutions...
Thank you!
Jim.
EDIT:
I should have written:
(
(+x && -1)
instead of(x && -1)
) in order to handlesign('abc')
properly (--> NaN)IE 11 不支持 Math.sign。我将最佳答案与 Math.sign 答案相结合:
现在,可以直接使用 Math.sign。
Math.sign is not supported on IE 11. I am combining the best answer with Math.sign answer :
Now, one can use Math.sign directly.
这是一个紧凑版本:
如果您想处理
NaN
和其他边缘情况,请使用这个(虽然它更长):如果您希望
sign(0)
返回0 以及:Here is a compact version:
If you want to deal with
NaN
and other edge cases, use this (it is longer though):If you want
sign(0)
to return 0 as well: