ビットごとのOR 0を使用して数値をフロア


192

私の同僚は、ビットごとまたは以下を使用して浮動小数点数をフロアする方法に出くわしました。

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

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

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

ありがとう。


6
欠点:2 ^ 31-1までしか機能せず、約20億(10 ^ 9)です。最大数の値は約10 ^ 308 btwです。
サイムVIDAS

12
例:3000000000.1 | 0-1294967296と評価されます。したがって、この方法はお金の計算には適用できません(特に、10進数を避けるために100を掛ける場合)。
サイムVIDAS

13
@ŠimeVidasFloatsは、お金の計算にも使用しないでください
ジョージリース、

20
フローリングではなく、切り捨てられます(0に向かって丸められます)。
パルトロミエザレウスキー

3
@sequence 0.1 + 0.2 == 0.3JavaScriptコンソールに入力してみてください。言語でサポートされている場合は、10進数型を使用する必要があります。そうでない場合は、代わりにセントを格納します。
Alex Turpin

回答:


160

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

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

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

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

欠点はありますか?多分それはいくつかのケースでは動作しませんか?私たちはそれを理解しなければならなかったので、明快さは明白なものです、そしてまあ、私はこの質問を書いています。

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

9
@haroldは確かに、実際には丸められないため、単に切り捨てられます。
Alex Turpin

5
もう1つの考えられる欠点はMath.floor(NaN) === NaN、その間(NaN | 0) === 0です。一部のアプリケーションでは、その違いが重要になる場合があります。
Ted Hopp 2013年

4
jsperfは、ループ不変のコードモーションが原因で、Chromeの空のループのパフォーマンス情報を生成しています。少し良いパフォーマンステストは次のようになります。jsperf.com
Sam Giles

4
これはasm.js(私が最初に知った)の標準的な部分です。Mathオブジェクトの関数、つまりのようにいつでも置き換えることができる関数を呼び出さないため、他の理由がない場合は高速ですMath.floor = function(...)
gman 2017年

3
(value | 0) === value値が実際には整数であり整数のみであることを確認するために使用できます(リンクされているElmソースコード@ dwayne-crooksのように)。またfoo = foo | 0、任意の値を整数に強制するために使用できます(32ビットの数値は切り捨てられ、すべての非数値は0になります)。
David Michael Gregg

36

これは、フローリングではなく切り捨てです。ハワードの答えはちょっと正しいです。しかし、私はMath.floorそれが負の数に関して想定されていることを正確に行うことを付け加えます。数学的には、それがフロアです。

上記で説明したケースでは、プログラマは小数点を切り捨てたり、小数を完全に切り取ったりすることに、より興味を持っていました。ただし、使用した構文は、floatをintに変換しているという事実を覆い隠しています。


7
これは正解ですが、受け入れられたものは正しくありません。それに加えMath.floor(8589934591.1)、予想される結果を生成する、8589934591.1 | 0 しません
Salman A

21

ECMAScript 6では、同等のもの|0Math.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

6
Math.trunc()2 ^ 31以上の数で機能し、| 0機能しないという事実を除く
Nolyurn

10

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


5

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

Math.floor これを念頭に置いて動作します。

ビット演算は、32ビットの符号付き整数で機能します。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

また。ビット演算は「フロア」ではありません。彼らは切り捨てます。これは言うのと同じで、に最も近い丸め0です。あなたが負の数に回るたら、Math.floorラウンドダウンながら、ビット単位で丸め開始アップ

前に述べたように、Math.floor64ビット浮動小数点数で動作するため、より安全です。ビットワイズの方が高速ですが、32ビットの符号付きスコープに制限されています。

要約する:

  • から作業する場合、ビットワイズは同じように機能し0 to 2147483647ます。
  • から作業する場合、ビットワイズは1オフです-2147483647 to 0
  • Bitwiseは、より小さい-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);
}

5
  • 仕様によると、整数に変換されます:

    lnumをToInt32(lval)とします。

  • パフォーマンス:これは以前にjsperfでテストされています。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.