web-dev-qa-db-ja.com

javascriptのNumber.sign()

数字の符号を見つけるための重要な方法があるかどうか疑問に思います( signum function )?
明白なものよりも短く/速く/エレガントなソリューションになります

_var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
_

短い抜粋

これを使用すると、安全かつ迅速になります

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

結果

今のところ、これらのソリューションがあります。


1。明らかで速い

_function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
_

1.1。kbec からの変更-1つの型のキャストが少なく、パフォーマンスが高く、短くなりました[fastest]

_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

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)が魔法の最適化を行うようで、このソリューションは2つの余分な操作を含み、論理的には決してないにもかかわらず、(1.1速くすることはできません。

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

道具

改善は大歓迎です!


[オフトピック]受け入れられた回答

  • アンドレイ・タランソフ -アートは+100ですが、悲しいことに、明白なアプローチよりも約5倍遅いです

  • FrédéricHamidi -どういうわけか、最も書かれた答え(執筆中)で、それはちょっとクールですが、間違いなく物事のやり方ではありません、私見。また、無限大の数値も正しく処理しません。これも数値です。

  • kbec -明らかな解決策の改善です。それほど革新的ではありませんが、すべてをまとめると、このアプローチが最善だと思います。彼に投票:)

100
disfated

高速ソリューションのよりエレガントなバージョン:

var sign = number?number<0?-1:1:0
79
kbec

数値を絶対値で割ると、その符号も得られます。短絡論理AND演算子を使用すると、特殊なケース0そのため、最終的には分割されません。

var sign = number && number / Math.abs(number);
28

探している関数は signum と呼ばれ、実装する最良の方法は次のとおりです。

function sgn(x) {
  return (x > 0) - (x < 0);
}
24

これはJavaScript(ECMAScript)の符号付きゼロをサポートしませんか? 「megafast」関数で0ではなくxを返すときに機能するようです:

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です。
13
Martijn

最新のブラウザで何が起こっているかに興味がある人のために、ES6バージョンにはネイティブ Math.sign メソッドがあります。 ここでサポート を確認できます。

基本的に、-110、またはNaNを返します。

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
10
Salvador Dali
_var sign = number >> 31 | -number >>> 31;
_

Infinityを必要とせず、数値が整数であることを知っている場合、openjdk-7ソースにある超高速:Java.lang.Integer.signum()

4
Toxiro

楽しみのためだけにこれを追加すると思った。

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

0およびNaNは-1を返します
+/- Infinityで正常に動作します

1
jaya

すべての数値、および0-0、およびInfinity-Infinityで機能するソリューションは次のとおりです。

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

詳細については、「 + 0と-0は同じですか? 」の質問を参照してください。


警告:現在標準となっている Math.sign を含め、これらの回答はいずれも0-0の場合には機能しません。これはあなたにとって問題ではないかもしれませんが、特定の物理学の実装では問題になるかもしれません。

1
Andy Ray

Martijnの答えに非常に似ています

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

もっと読みやすいと思います。また(または、あなたの視点に応じて)、数値として解釈できるものもグロッキングします。たとえば、-1を指定すると、'-5'を返します。

0
equaeghe

数値をビットシフトし、最上位ビット(MSB)を確認できます。 MSBが1の場合、数値は負です。 0の場合、数値は正(または0)です。

0
Brombomb

Math.signから-0と0を返すという実用的な意味はないので、私のバージョンは:

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
0

Math.signと同じ結果を返す関数、つまりsign(-0)-> -0、sign(-Infinity)-> -Infinity、sign(null)-> 0 、sign(undefined)-> NaNなど.

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

Jsperfはテストまたはリビジョンを作成させません。テストを提供できないことをごめんなさい(jsbench.github.ioを試してみましたが、結果はJsperfよりも互いに近いようです...)

誰かがそれをJsperfリビジョンに追加してください、私がそれが以前に与えられたすべてのソリューションとどのように比較するのか興味があります...

ありがとうございました!

ジム。

[〜#〜] edit [〜#〜]

私は書くべきだった:

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

sign('abc')を適切に処理するための_(+x && -1)_ではなく、_(x && -1)_(-> NaN)

0
Jimshell

私はちょうど同じ質問をしようとしていましたが、私が書き終える前に解決策に来ました、この質問はすでに存在していましたが、この解決策は見ませんでした。

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

(n >> 31) + (n>0?1:0)

0
Moritz Roessler