web-dev-qa-db-ja.com

ビット単位OR 0を使用して数値をフロアリングする

私の同僚は、ビット単位または以下を使用して浮動小数点数をフロアリングする方法を見つけました。

var a = 13.6 | 0; //a == 13

私たちはそれについて話していて、いくつかのことを考えていました。

  • どのように機能しますか?私たちの理論では、このような演算子を使用すると、数値が整数にキャストされ、小数部分が削除されます。
  • Math.floorを実行するよりも利点がありますか?多分それは少し速いですか? (意図しないしゃれ)
  • 欠点はありますか?場合によっては機能しないのでしょうか?明快さは明らかです。私たちはそれを理解しなければならなかったので、まあ、私はこの質問を書いています。

ありがとう。

175
Alex Turpin

どのように機能しますか?私たちの理論では、このような演算子を使用すると、数値が整数にキャストされ、小数部分が削除されます。

符号なし右シフト_>>>_を除くすべてのビット演算は、符号付き32ビット整数で機能します。したがって、ビット演算を使用すると、floatが整数に変換されます。

Math.floorを実行するよりも利点はありますか?多分それは少し速いですか? (意図しないしゃれ)

http://jsperf.com/or-vs-floor/2 は少し速いようです

欠点はありますか?場合によっては機能しないのでしょうか?明快さは明らかです。私たちはそれを理解しなければならなかったので、まあ、私はこの質問を書いています。

  • JsLintを渡しません。
  • 32ビット符号付き整数のみ
  • 奇数の比較動作:Math.floor(NaN) === NaN、一方_(NaN | 0) === 0_
139
Joe

これは、フローリングとは対照的にtruncationです。ハワードの答えは一種の正しいものです。しかし、私はそれを追加しますMath.floorは、負の数に関して想定されていることを正確に行います。数学的には、それがフロアです。

上記の場合、プログラマはtruncationに興味があるか、または小数点を完全に切り落とすことに興味がありました。しかし、彼らが使用した構文は、彼らがフロートをintに変換しているという事実を曖昧にします。

28
Chad La Guardia

ECMAScript 6では、|0に相当するものは Math.trunc です。

小数桁を削除して、数値の整数部を返します。引数が正の数であるか負の数であるかに関係なく、ドットとその後ろの数字を切り捨てます。

Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN
18
zangw

最初の点は正しいです。数値は整数にキャストされるため、小数桁は削除されます。その点に注意してください Math.floorは、負の無限大に向かって次の整数に丸められるため、負の数に適用すると異なる結果が得られます。

10
Howard
  • 仕様には、整数に変換されると書かれています:

    LnumをToInt32(lval)とします。

  • パフォーマンス:これは、以前に jsperf でテストされました。

注:仕様へのデッドリンクが削除されました

5
pimvdb

JavascriptはNumber倍精度64ビット浮動小数点数 として表します。

Math.floorはこれを念頭に置いて機能します。

ビット演算は、32ビットsigned整数で機能します。 32ビットの符号付き整数は、最初のビットを負の記号として使用し、他の31ビットは数値です。このため、許可される32ビットの符号付き数値の最小数と最大数は、それぞれ-2,147,483,648と2147483647(0x7FFFFFFFF)です。

したがって、| 0を実行しているとき、基本的に& 0xFFFFFFFFを実行しています。つまり、0x80000000(2147483648)以上で表される数値はすべて負の数として返されます。

例えば:

 // Safe
 (2147483647.5918 & 0xFFFFFFFF) ===  2147483647
 (2147483647      & 0xFFFFFFFF) ===  2147483647
 (200.59082098    & 0xFFFFFFFF) ===  200
 (0X7FFFFFFF      & 0xFFFFFFFF) ===  0X7FFFFFFF

 // Unsafe
 (2147483648      & 0xFFFFFFFF) === -2147483648
 (-2147483649     & 0xFFFFFFFF) ===  2147483647
 (0x80000000      & 0xFFFFFFFF) === -2147483648
 (3000000000.5    & 0xFFFFFFFF) === -1294967296

また。ビット演算は「床」になりません。それらはtruncateで、これは0に最も近いと言うことと同じです。負の数に移動すると、Math.floordownを丸め、ビット単位の丸めupを開始します。

前にも言ったように、Math.floorは64ビット浮動小数点で動作するため、より安全です。ビット単位は高速です、はい、ただし32ビット符号付きスコープに制限されています。

要約する:

  • 0 to 2147483647から作業する場合、Bitwiseは同じように機能します。
  • -2147483647 to 0で作業している場合、ビット単位は1桁オフです。
  • ビット単位は、-2147483648より小さい数値と2147483647より大きい数値では完全に異なります。

あなたが本当にパフォーマンスを微調整して両方を使用したい場合:

function floor(n) {
    if (n >= 0 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    if (n > -0x80000000 && n < 0) {
      return (n - 1) & 0xFFFFFFFF;
    }
    return Math.floor(n);
}

Math.truncを追加するだけで、ビット演算のように機能します。だからあなたはこれを行うことができます:

function trunc(n) {
    if (n > -0x80000000 && n < 0x80000000) {
      return n & 0xFFFFFFFF;
    }
    return Math.trunc(n);
}
2
ShortFuse