Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubys Bitwise Toolbox:演算子、アプリケーション、および魔法のトリック

Railsアプリの構築に一生を費やすことができ、ビット演算子を使用する必要はありません。プログラミングに不慣れな場合は、「ビット単位」が何を意味するのかさえわからないかもしれません。

しかし、効率が重要でリソースが限られているシステムに関心を持った瞬間、ビット単位の操作が重要になります。これらは、ネットワークプロトコル、暗号化、Unixファイルのアクセス許可、組み込みシステムなどで広く使用されています。

さらに、コンピューターが2つの数値を加算するなどの動作を実際に理解するには、ビット演算を理解する必要があります。

Rubyや他の多くの言語はネイティブサポートを備えているため、将来それらに遭遇した場合に何が起こっているのかを理解するだけであっても、ツールボックスに追加するのに最適なツールです。

この記事では、ビット演算とは何か、それらを適用できる場所の例、およびRubyでそれらを最適に使用する方法について説明します。始めましょう。

ビット演算とは何ですか?

どのコンピューターの最下位レベルでも、ビットとも呼ばれる1と0しかありません。 Rubyまたは他のプログラミング言語で使用するその他の操作は、最終的に1と0として格納されますが、コンピューターのソフトウェアは、表示されるものと実際に格納されるものの間で効果的に変換します。たとえば、文字列「hello」を1と0のチェーンとして格納します。

ビット単位の演算を使用すると、通常は数値を表すこれらのビットに直接アクセスし、それらを使用して「何か」を実行できます。一部の操作は、ソフトウェアに機能をよりエレガントで効率的な方法で実装するのに役立ちます。

今のところビット演算について強調すべき2つの重要な側面があります。ビットを直接使用しているため、情報の格納に非常に効果的であり、実行が非常に高速です。

基本的な動作は、ビットのセットを持ち、それに演算子を適用することです。 2セットのビットで演算子を使用することもできます。いくつかの操作を見てみましょう:

ビット演算ではありません

これは単項演算です。つまり、ビットのセットにのみ適用され、1を0に、またはその逆に置き換えるのと同じくらい簡単です。記号で表されます:~

~101000 = 010111
およびビット演算

ANDは、2セットのビットに適用される演算です。そのシンボルは&です そしてそれはこの論理に従います:

1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0

したがって、2つの等しい長さのビットのセットがある場合、結果はこのロジックを個々のペアに適用するだけです。

0110 AND
0111
-----
0110

Rubyの場合:

25.to_s(2)           # 11001
30.to_s(2)           # 11110
(25 & 30).to_s(2)    # 11000
またはビット演算

AND演算と同様に、2セットのビットにも適用される別の演算はビット単位のORです。そのシンボルは|です そしてこの論理に従います:

1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0

したがって、いずれかの側に1がある場合、結果は1になり、それ以外の場合は0になります。非常に単純です。より多くのビットを使用したOR演算を見てみましょう:

0110 OR
0111
-----
0111

そしてRubyで:

25.to_s(2)           # 11001
30.to_s(2)           # 11110
(25 | 30).to_s(2)    # 11111

実際の例1:権限

この時点で、なぜこれらの操作が役立つのか疑問に思われるかもしれません。結局のところ、それらはかなり低レベルのようです。ネットワークプロトコル、グラフィックス、または暗号化を直接操作する予定はない場合があります。

ただし、おそらく以前に権限を使用したことがあります。パーミッションは、ビット演算が非常に役立つ領域の1つです。ユーザーがドキュメント内でさまざまなアクションを実行できる権限システムがあるとします。

  • 表示
  • 編集
  • 削除
  • 他のユーザーを招待する

そして今、これらのアクションをさまざまな役割にモデル化したいと思います:

  • アシスタント: ドキュメントを表示および編集できます。
  • オブザーバー: ドキュメントのみを表示できます。
  • 作成者: すべてのアクションを実行できます。

これをどのようにモデル化できますか?ユーザーがこれらの役割のいずれかを持っているかどうかをいつでも知るにはどうすればよいですか? 1つの答えは、ビット演算を使用することです。

ユーザーごとに、ユーザーが持っている権限を表すビットのセットを1つだけ保存します。

(Starting from the right side)
1st bit: View
2nd bit: Edit
3rd bit: Delete
4th bit: Invite other users

例:

0001 = Can only view the document.
0011 = Can view and edit the document.
1001 = Can view, can't edit, can't delete and can invite others.

一部のユーザーにこれらの値を設定すると、必要な権限で非常に高速な比較を行うことができます。ユーザーがドキュメントを編集できるかどうかを確認しているとしましょう。ビットごとのAND演算を使用できます:

# This is called a bit mask. It contains only the value we want to check, in this case the second bit for editing.
EDIT_PERMISSION_MASK = 0b0010

# We can define a quick method to check this: 
def can_edit_document?(user_permisions)
  (EDIT_PERMISSION_MASK & user_permisions) != 0
end

これは、ビットごとのAND演算で0とは異なるものが得られる場合、そのビットが設定されていることを意味します。

0010 AND
1101
----
0000 == 0 so we don't have the permission

0010 AND
1110
----
0010 != 0 so we have the permission

チェックするビットの位置を変更することで、他のパーミッションに同じロジックを適用できるため、これらの定数と対応するメソッドを使用することになります。

VIEW_PERMISSION_MASK   = 0b0001
EDIT_PERMISSION_MASK   = 0b0010
DELETE_PERMISSION_MASK = 0b0100
INVITE_PERMISSION_MASK = 0b1000

さらに、簡単なビットチェックで、アクセス許可を動的に定義し、将来的に新しいアクセス許可を保存できます。

たとえば、アシスタントはドキュメントの表示と編集のみが可能であるため、そのユーザーの権限は0011になります。 。その値をデータベースに保存してから、アシスタントが前に定義したメソッドでアクションを実行できるかどうかを簡単に確認できます。

ASSISTANT_MASK = VIEW_PERMISSION_MASK | EDIT_PERMISSION_MASK
# This will be: 0011

# Optionally, we could use this method to check if this user is an assistant. This method could be defined inside the User class.
def is_assistant?(user)
  (user.permissions == ASSISTANT_MASK)
end

これらすべてがおなじみのように聞こえる場合、それはUnixベースのシステムのファイルパーミッションに一般的に使用されているのと同じアプローチだからです。

実際の例2:チーム内のポジション

もう少しビット単位の演算を使用しましょう😉。

比較的一般的な別のケース、つまりスポーツチームのさまざまな役職や会社の役職に適用できます。単純化するためにバスケットボールチームと一緒に行きましょう。

バスケットボールでは、ゲームをプレイするときに5つのポジションがあります。-ポイントガード-シューティングガード-スモールフォワード-パワーフォワード-センター

そして、各位置にビットのセットを割り当てることができます: 00001 Point guard 00010 Shooting guard 00100 Small forward 01000 Power forward 10000 Center

Rubyでも同じです:

POINT_GUARD_POSITION    = 0b00001
SHOOTING_GUARD_POSITION = 0b00010
SMALL_FORWARD_POSITION  = 0b00100
POWER_FORWARD_POSITION  = 0b01000
CENTER_POSITION         = 0b10000

POINT_GUARD_POSITION | SHOOTING_GUARD_POSITION | SMALL_FORWARD_POSITION | POWER_FORWARD_POSITION | CENTER_POSITION # = 31

これで、チーム全体が参加しているかどうかを確認するなど、いくつかの興味深いことができるようになりました。

# p1...p5 are the positions of each player
is_full_team_present = (p1 | p2 | p3 | p4 | p5 == 31)

なんで?ビット単位のOR演算を実行することにより、すべての位置があれば、最終的には11111になります。

# OR bitwise operation
00001 |
00010 |
00100 |
01000 |
10000
-----
11111

また、2 ^ 0 + 2 ^ 1 + 2 ^ 2 + 2 ^ 3 + 2 ^ 4 =31であるため、11111は31です。

これは厳密にはビット演算とは関係ありませんが、このデータモデリングを使用すると、2人のプレーヤーを交換できるかどうかを確認することもできます。これは非常に簡単です:

def can_be_exchanged?(player1, player2)
  player1.position == player2.position
end

XOR

2セットのビットで実行できるもう1つの操作は、シンボルが^であるXORです。 。

XORは排他的論理和を意味し、次のロジックに従います:

1 | 1 = 0
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0

したがって、2つのビットの1つが1の場合にのみ、結果は1になります。両方が等しい場合は0になります。

x ^ x =0であるため、この演算は、数値をそれ自体と比較するために一部のアルゴリズムで使用されます。

シフト

これは、セット内でビットを一方または他方に「移動」する興味深い操作のグループです。説明させてください。

ビットシフトを使用して、ビットを左または右の一方向に移動または「シフト」します。

00010111 left-shift
<-------
00101110
10010111 right-shift
------->
11001011

ビットをn回移動またはシフトできます。これは、Rubyで5番に2回適用された左シフトです:

5.to_s(2) # 101
(5 << 2).to_s(2) # 10100

ご覧のとおり、左シフトは<<で表されます。右シフトは>>:

を使用します
5.to_s(2) # 101
(5 >> 2).to_s(2) # 1

この場合、1 * 01のビット「0」と「1」が1つしかないためです。 *破棄されました。

右シフトで2で割ります

ビットシフトに関する興味深い事実の1つは、ビットシフトを使用していくつかの数学演算を計算できることです。以前はこれが高速でしたが、現在では、ゲーム開発などのリソースでより多くの制約を処理するプログラマーによってほぼ独占的に使用されています。

数値に右シフトを適用すると、2で割った結果が得られます。

10.to_s(2)        # 1010
(10 >> 1).to_s(2) # 101
10 >> 1           # 5
左シフトで2を掛ける

同様に、左シフトで2を掛けることができます:

10.to_s(2)        # 1010
(10 << 1).to_s(2) # 10100
10 << 1           # 20
数値が奇数か偶数かをすばやく確認

非常に高速で簡単に実行できるビット演算の非常に単純な例があります。

1でAND演算を実行するとします。これは、使用しているコンピューターに応じて、任意の数の0になります。1。2で実行しましょう。

2 = 00000010 &
    00000001
-------------
    00000000

今4:

4 = 00000100 &
    00000001
-------------
    00000000

5はどうですか?

5 = 00000101 &
    00000001
-------------
    00000001

これで1になりました。これが何を意味するのか推測できますか?

これを実行し、1を使用すると、数値が偶数の場合は0になります。奇数の場合は、1になります。この事実を使用して、Rubyでいくつかのメソッドを簡単に作成できます。

def is_odd?(number)
  number & 1
end
def is_even?(number)
  is_odd?(number) == 0
end
# Or:
def is_even?(number)
  (number & 1) == 0
end

さらに進んだり、ビットで驚異的な瞬間を体験したい場合は、このビット単位のハックコレクションでその他のトリックを確認してください。

結論

ビット単位の操作は、一度も遭遇したことがない場合は理解するのが難しいですが、慣れれば、それらを使用する既存または将来のプロジェクトに対処する準備が整います。さらに、コードの問題の解決策を計画するときに、新しいツールを利用できます。


  1. Windows10のヒントとコツ

    Windows 10は、最初の1年間はWindows8.1およびWindows7ユーザーへの無料アップグレードとして提供されており、Microsoftによって10年間サポートされます。新しいオペレーティングシステムには、いくつかの優れた新機能など、提供できるものがたくさんあります。 Windows10のヒントとコツを確認してみましょう それはあなたがそれを最大限に活用するのに役立ちます。 Windows10のヒントとコツ 初心者の方は、まずWindows10PCの基本的な使用方法のチュートリアルをお読みください。 1]Windows10を希望どおりに動作させる コントロールパネ

  2. Windows10のヒントとコツ

    Windows 10は、最初の1年間はWindows8.1およびWindows7ユーザーへの無料アップグレードとして提供されており、Microsoftによって10年間サポートされます。新しいオペレーティングシステムには、いくつかの優れた新機能など、提供できるものがたくさんあります。 Windows10のヒントとコツを確認してみましょう それはあなたがそれを最大限に活用するのに役立ちます。 Windows10のヒントとコツ 初心者の方は、まずWindows10PCの基本的な使用方法のチュートリアルをお読みください。 1]Windows10を希望どおりに動作させる コントロールパネ