Panda Noir

JavaScript の限界を究めるブログです。

JavaScriptでsign関数をビットを用いて実装

sinではなくsign関数です。受け取った数値が正の数か負の数か0かを返します。

まず原始的実装

sign関数は簡単に実装すると以下のようになります。

function sign(n){
    return n===0?0:n>0?1:-1;
}

もう少し短くするとこんなかんじです

function sign(n){
    return n>0?1:n<0?-1:0;
}

多分限界まで短いのはこんなかんじです

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

ビットを用いて実装

しかしこれでは味気ないので折角です、ビット整数の知識を用いて書いてみましょう。

まず整数を32ビット符号付き整数に変換します。すると、初めのビットが符号を表すようになります。初めのビットが0なら正の数、1なら負の数となります。

ただ、これでは0も正の数と判定されてしまいます。悔しいですが、私ではこれはビットを用いて判定できないので別処理にします。うまくできそうなんですがね…

function sign(n){
    return !n?0:(n|0)>>>31?-1:1;
}

もうすこしだけ改善。

function sign(n){
    return -(n>>>31)||(n?1:0);
}

短くなりましたが、-を判定する部分以外は普通にやってしまっているので残念ですね。なんとかできそうなのですが…

おまけ: 速度測ってみた

ビットを使わない原始的実装をsign1、ビットを使う実装をsign2とします。計測は以下のコードで行いました(sign関数はそれぞれsign1、sign2に変更して測定しました)。

console.time('sign');
for(var i=0;i<1000000;i=0|i+1){
    sign(1);
    sign(10);
    sign(12345);
    sign(-1);
    sign(-10);
    sign(-1);
    sign(0);
}
console.timeEnd('sign');

結果はどちらも平均5msくらいでほぼ違いがありませんでした。ちょっとsign1が早かったかな、というくらいです。