105

想知道是否有任何重要的方法可以找到数字的符号(符号函数)?
可能比显而易见的解决方案更短/更快/更优雅

var sign = number > 0 ? 1 : number < 0 ? -1 : 0;

简短的回答!

使用它,你会安全又快速(来源:moz

if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };

您可能想查看性能和类型强制比较小提琴

很长一段时间过去了。进一步主要是出于历史原因。


结果

目前我们有以下解决方案:


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) -> NaNsign("0") -> NaN

as ofInfinity是 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 - 是对明显解决方案的改进。不是革命性的,但综合起来,我认为这种方法是最好的。投票给他:)

4

16 回答 16

80

更优雅的快速解决方案:

var sign = number?number<0?-1:1:0
于 2012-01-31T12:32:30.673 回答
29

将数字除以其绝对值也给出了它的符号。使用短路逻辑 AND 运算符允许我们进行特殊情况0,因此我们最终不会除以它:

var sign = number && number / Math.abs(number);
于 2011-10-02T06:26:17.627 回答
25

您正在寻找的功能称为signum,实现它的最佳方式是:

function sgn(x) {
  return (x > 0) - (x < 0);
}
于 2013-01-19T20:05:40.307 回答
14

这不应该支持 JavaScript(ECMAScript)的签名零吗?在“megafast”函数中返回 x 而不是 0 时,它似乎有效:

function sign(x) {
    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN;
}

这使其与ECMAScript 的 Math.sign ( MDN ) 草案兼容:

返回 x 的符号,指示 x 是正数、负数还是零。

  • 如果 x 为 NaN,则结果为 NaN。
  • 如果 x 为 -0,则结果为 -0。
  • 如果 x 为 +0,则结果为 +0。
  • 如果 x 为负而不是 -0,则结果为 -1。
  • 如果 x 为正而不是 +0,则结果为 +1。
于 2014-01-22T21:46:01.587 回答
12

对于那些对最新浏览器发生的事情感兴趣的人,在 ES6 版本中有一个原生的Math.sign方法。您可以在此处查看支持

基本上它返回-1, 1,0NaN

Math.sign(3);     //  1
Math.sign(-3);    // -1
Math.sign('-3');  // -1
Math.sign(0);     //  0
Math.sign(-0);    // -0
Math.sign(NaN);   // NaN
Math.sign('foo'); // NaN
Math.sign();      // NaN
于 2015-04-20T05:38:24.403 回答
4
var sign = number >> 31 | -number >>> 31;

如果您不需要 Infinity 并且知道数字是整数,则超快,可在 openjdk-7 源代码中找到:java.lang.Integer.signum()

于 2014-04-24T07:51:18.383 回答
1

我想我会添加这个只是为了好玩:

function sgn(x){
  return 2*(x>0)-1;
}

0 和 NaN 将返回 -1
在 +/-Infinity 上工作正常

于 2014-08-24T10:42:02.980 回答
1

适用于所有数字以及0-0以及Infinity和的解决方案-Infinity是:

function sign( number ) {
    return 1 / number > 0 ? 1 : -1;
}

有关更多信息,请参阅问题“ +0 和 -0 是否相同? ”。


警告:这些答案,包括现在的标准,都不Math.sign适用于 case 0vs -0. 这对你来说可能不是问题,但在某些物理实现中它可能很重要。

于 2016-01-04T23:18:34.340 回答
0

您可以对数字进行位移并检查最高有效位 (MSB)。如果 MSB 为 1,则该数字为负数。如果为 0,则该数字为正数(或 0)。

于 2011-10-02T06:40:05.250 回答
0

我刚要问同样的问题,但是在我写完之前找到了一个解决方案,看到这个问题已经存在,但没有看到这个解决方案。

(n >> 31) + (n > 0)

通过添加三元组似乎更快(n >> 31) + (n>0?1:0)

于 2013-09-26T10:08:29.680 回答
0

与Martijn的答案非常相似的是

function sgn(x) {
    isNaN(x) ? NaN : (x === 0 ? x : (x < 0 ? -1 : 1));
}

我觉得它更具可读性。此外(或者,取决于您的观点),它还可以理解可以解释为数字的事物;例如,它-1在呈现时返回'-5'

于 2014-05-15T14:00:54.363 回答
0

我没有看到任何返回 -0 和 0 的实际意义,Math.sign所以我的版本是:

function sign(x) {
    x = Number(x);
    if (isNaN(x)) {
        return NaN;
    }
    if (x === -Infinity || 1 / x < 0) {
        return -1;
    }
    return 1;
};

sign(100);   //  1
sign(-100);  // -1
sign(0);     //  1
sign(-0);    // -1
于 2016-11-30T12:05:37.563 回答
0

我知道的方法如下:

数学符号(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,并且not NaN]) 然后使用按位或运算来组合这些位。

这似乎是所有浏览器中平均性能最好的(至少在 Chrome 和 Firefox 中是最好的),但并不是所有浏览器中最快的。出于某种原因,三元运算符在 IE 中更快。

n?n<0?-1:1:0

var s = n?n<0?-1:1:0;

由于某种原因,在 IE 中速度最快。

jsPerf

执行的测试:https ://jsperf.com/get-sign-from-value

于 2017-09-30T21:32:18.257 回答
0

我的两分钱,具有返回与 Math.sign 相同结果的函数,即 sign(-0) --> -0, sign(-Infinity) --> -Infinity, sign(null) --> 0 , 符号(未定义)-> NaN 等。

function sign(x) {
    return +(x > -x) || (x && -1) || +x;
}

Jsperf 不会让我创建测试或修订版,很抱歉无法为您提供测试(我已经尝试过 jsbench.github.io,但结果似乎比 Jsperf 更接近...)

如果有人可以将它添加到 Jsperf 修订版中,我很想知道它与以前给出的所有解决方案相比如何......

谢谢!

吉姆。

编辑

我应该写:

function sign(x) {
    return +(x > -x) || (+x && -1) || +x;
}

(+x && -1)而不是(x && -1))为了sign('abc')正确处理(-> NaN)

于 2018-02-12T19:12:44.127 回答
0

IE 11 不支持 Math.sign。我将最佳答案与 Math.sign 答案相结合:

Math.sign = Math.sign || function(number){
    var sign = number ? ( (number <0) ? -1 : 1) : 0;
    return sign;
};

现在,可以直接使用 Math.sign。

于 2019-10-25T16:11:32.883 回答
0

这是一个紧凑的版本:

let sign=x=>2*(x>=0)-1
//Tests
console.log(sign(0)); //1
console.log(sign(6)); //1
console.log(sign(Infinity)); //1
console.log(sign(-6)); //-1
console.log(sign(-Infinity)); //-1
console.log(sign("foo")); //-1

如果您想处理NaN和其他边缘情况,请使用它(虽然它更长):

let sign=x=>isNaN(x)?NaN:2*(x>=0)-1
//Tests
console.log(sign(0)); //1
console.log(sign(6)); //1
console.log(sign(Infinity)); //1
console.log(sign(-6)); //-1
console.log(sign(-Infinity)); //-1
console.log(sign("foo")); //NaN

如果你也想sign(0)返回 0:

let sign=x=>isNaN(x)?NaN:(x?2*(x>=0)-1:0)
//Tests
console.log(sign(0)); //0
console.log(sign(6)); //1
console.log(sign(Infinity)); //1
console.log(sign(-6)); //-1
console.log(sign(-Infinity)); //-1
console.log(sign("foo")); //NaN
于 2021-03-30T07:08:33.307 回答