■ ビット演算 【 Python 3.9 】 | @Kay-nea@のブログ

@Kay-nea@のブログ

アメブロ初心者なのでよく解っていませんが、始めてみました。

(*)FacebookとInstagramはやっていません。

 機材を制御する場合、二値の判定を用いますが、これは、電気信号がそうなっているという理由ではなく、折り機のように上糸と下糸の状態をパターンで制御する場合、孫五社の上下と言う座標管理が二値で行えていたので、そう言ったパターンをパンチカードで制御するようになりました。これが自動織機の歴史であり、コンピューターの基礎部分ができがある前身の部分になります。プログラムミングが出来る物とそうでない物では全く異なるのですが、この違いを知る場合、ブレッドボードを使った回路を組んでみるのが一番わかりやすいと思います。

 

 ブレッドボードで全く違う振る舞いをする物を用意しようと思うと、出力用のデバイスが共通していても、蟻後リズムが異なる場合、回路自体を変更する必要があります。プログラミングが不能なアナログデバイスで異なる挙動を実装する場合だと実装る挙動分だけ回路を作る必要があります。

 

 ブレッドボードでの制御でも、このプラスとマイナスとGND(グラウンド。)からの信号をGPIOから出力して、その端子の信号をコンピューターやIOT端末で制御した場合、必要な挙動をするための回路を実装しておく必要はありますが、パターン制御などはプログラムで制御する事が出来ます。

 

 その為、回路の動作は二値の信号ですが、制御をしているのは高級言語での制御になるので、文字列を使った制御プログラムを入力してそれを実行して二値の電気信号の制御をすることが出来るようになっています。

 

 二値の制御ですが、電気信号で考えると、オンとオフですから、一つの構造物に対して一つのオンとオフが存在します。それが回路内で分岐しているので、同時進行やラグを持たせた状態で動作している訳ですが、その信号を論理演算などで制御することで、二値の信号で10進数や16進数を作ったり計算をすることが出来るようになります。

 

 二進数はプログラミング言語でも使用できるようになっており、計算もできるようになっているのですが、この考え方が、ICなどを使わないアナログ回路を作る時と同じ考え方(と言っても係数Tがないので、論理演算回路と同じ考え方)になりますが、今回は、プログラミング言語で使用できるビット演算などについて少し触れようかなと思います。

 

 

ット演算                       

 

 ビット演算は、論理演算と同じなので、高校の数学で登場する命題と同じです。この場合、Pythonでは、

 

 

のような記号を使います。

 

 

 理和(OR回路の判定)             

 

 命題では 【 論理和 】 という形で出てきますが、これは、二進数を加算した時の結果と同じになるので、論理和と言います。

 

 OR回路ですが、マイクラでは、

 

 

のようなつなぎで実現できます。と言っても信号の逆流が発生するので、

 

 

のようになりますが、足し算で0以外で成立する条件なので、

 

 

のようないずれかの条件と、

 

 

のように両方の条件でも動作します。

 

 Pythonで、10進数と二進数を変換する場合、

 

 

のようにすると、二進数と10進数の変換ができます。2進数の場合、頭に0bを追加すると、10進数に変換でき、10進数を2進数に変換する場合には、bin()関数を使います。ちなみに、16進数の変換にはhex()関数を使います。

 

 

論理積(OR)については、bin()関数で処理をしますが、この時に演算記号を用いて処理を行うと、

 

のようになります。これを見てもらうと、0と0の以外は全て1になっています。その為、

 

【 二者を比較した場合に、いずれかに1がある場合には1になり、

  0と0の組み合わせの時に0になる処理 】              

 

になります。

 

 

 理積(AND回路の判定)            

 

 論理積は二進数の二つの数値を掛け合わせた時の結果と同じになるので、論理積と言います。マイクラでは、

 

 

のような回路になりますが、

 

 

のように1X1の時だけ1と言うTRUE(真)になり、それ以外はFALSE(偽)になります。

 

 

Pythonで桁数を持つ二進数で判定を行ってみると、

 

 

のようになり、双方に1がある場所だけ1になり、それ以外は0になります。また、桁が存在しない場合には、1になる条件が存在しない場合には0になります。

 

 

 他的論理和(XOR回路の判定)        

 

 排他的論理和は、片方だけがTRUE(真)の時に条件が成立します。

 

 桁だけを見ると、 【 繰り上がりを捨てる足し算 】 になります。その為、0 + 0 = 0 は0になりますが、1 + 1 = 2 = 0b10 と言うのが二進数の足し算ですがこの時の繰り上がりを切ると0になるので、FALSE(偽)になります。その為、片方のみがTRUE(真)の時だけ動作する仕様になっています。

 

 マイクラでは、レッドストーン比較器を減算モードで並べて使うと作る事が出来ますが、

 

 

のように0同士と1同士の条件だとFALSE(偽)になります。ただし、片方の信号がTRUE(真)の時には、

 

 

のようにTRUE(真)になります。Pythonで実行してみると、

 

 

のような結果になります。ちなみに、XORですが、同じ値で二度XORを行うと元に戻るという性質があります。

 

     a ^ b ^ b → a

 

これをPythonで実行してみると、

 

 

のようになります。また、

 

     a ^ b ^ a → b

 

のように、元の値を消す事もできます。

 

 

のようなことができます。

 

 

 理否定(NOT回路の判定)            

 

 これは、信号の反転と考えると解り易いのですが、符号が付きます。

 

 マイクラでは、

 

 

のような感じになりますが、Pythonで実行してみると、

 

 

のようになります。

 

 

 理積の否定(NAND回路)からの変化    

 

 ド・モルガンの法則を使うと、

 

    論理積(AND)

    論理和(OR)

    論理否定(NOT)

 

を使うと、全ての回路を組む事が出来るのですが、現在の集積ではNANDを用いたものが使用されています。NANDモジュールがある場合、そこから、上記の三つを作れるのですが、このNANDと言うのは、論理積(AND)を論理否定(NOT)で反転させたものになります。

 

 マイクラの場合、

 

 

になりますが、これを組み合わせるても回路を組めます。電気工作ではNANDのICがありますが、各論理演算回路のICを組み合わせて工作をしたほうがスペースを削減できるのでいいのですが、モジュールが単体で配線の組み方で別の回路が作れる場合、単一のモジュールを複製して、回路を組んだほうが都合がいいのでそう言った使い方をする場合もあります。

 

 最も簡単に変換できるのが、NOT回路で、これは、NANDの入力を統合すると、ANDの要素がなくなるので、NOT回路になります。マイクラでは、

 

 

を使いますが、前述のNANDモジュールで考えると、

 

 

のような構造になります。前述のOR回路は、

 

 

のような構造ですが、これは、NANDの入力をNOTにしたものになるので、

 

 

のようにNANDのモジュールを3つ用意すると作れます。AND回路をマイクラで使う場合には、

 

 

になりますが、NANDのモジュールから組み立てると、

 

 

のようにNANDの信号をNOTで否定するだけANDになるので、2つのモジュールだけでAND回路を作れます。

 

 論理演算回路については、

 

■ マイクラと回路 : 論理演算回路と信号の伝達

 

■ マイクラと回路 : 論理演算回路

 

■ つぶやき

 

 

でも触れていますが、条件の判定を行う場合に使用できます。レッドストーン回路のような二値の判定だと、ANDはフラグで、ORは回路の信号の判定を組み立てる時に使用して、NOTは二重否定や信号の延長などで使用しますが、

 

 

 

のような使い方もできますが、XORとANDを使うと、半加算器(HA)が作れるので、それを組み合わせて全加算器を作る事もできます。

 

 

 フトレジスター回路                

 

 マイクラでは回路を通過ったビット演算が可能ですが、計算をする場合には、加算のように桁の繰り上がりが発生します。基本的に、機械の演算は加算処理になりますが、こう書くと 【 引き算はどうなっているのだろう? 】 と思うかもしれません。

 

 ある意味、この謎の解に近い物は中学校の数学で登場するのですが、 【 数式は項の加算で構成されている 】 と言う内容を学ぶと、加算でも引き算が出来る事が解ります。ただし、電気信号の二値でマイナスの数値が出てくるわけがありませんから、項の考え方とは異なり、符号を持たない二進数同士の加算で引き算を行います。

 

 この時の登場するのが、 【 補数 】 になりますが、この補数を加算によって算出して、それをさらに加算して引き算を行います。

 

 こうした処理が可能なので、0と1しかない世界で二進数の計算が出来るので、10進数にデコードした時に10進数の引き算を行う事が出来ます。

 

 以前、ここで、 【 掛け算と割り算はループ処理 】 という事を書きました。プログラムは 【 順次 】 【 分岐 】 【 反復 】 の構造体になっていますが、この中の 【 反復 】 が掛け算と割り算の処理になります。この二つの計算方法ですが、

 

■ 掛け算(乗算)                    

 

    元の数を指定回数だけ足していく処理

 

■ 引き算(除算)                    

 

    元の数が0になるまで、対象の数を引いてく処理

 

になります。小学校の算数では、整数処理をする場合だと、割り切れない数値がある場合、 【 こたえ : ● と、あまり ■ 】 のような感じで書くと思いますが、この時の割算の余りを 【 剰余 】 と言います。この数値ですが、プログラミング言語では、組み込み関数で算出する事が出来ます。

 

 この条件を見ると、 【 加算が出来れば、四則演算が可能 】 で、乗算と除算はループ処理という事が確認できますが、小学校の算数では、筆算が登場します。桁の多い足し算だと二年生から筆算を行う事で計算しやすい方法を学ぶことになりますが、筆算をする時に桁の移動をすると思います。

 

 小学校3年生からは掛け算の筆算が登場しますが、この時に足し算の時には存在しなかった、 【 桁の移動 】 が発生します。掛け算と割り残では真逆に移動しますが、10進数の桁が左右に移動する計算方法を学びます。と言うか、計算技術で計算が速くなる手法と言う形で覚える事になりますが、これを覚えると、横書きの計算で桁数の多い物でも早く計算できるようになります。また、複数の数値の四則演算も行いやすくなるので、筆算の凄さというのは学んでみると効果てきめんですから、計算には必須な物として使用する事になります。

 

 普通に学習していると、 【 なぜ、桁が移動するのだろう? 】 と言う名素を持ったまま 【 そう言う技法 】 として覚える事になりますが、これと同じ考え方は、刃物を使う時に、物理法則を学ばなくても道具の使い方を覚えると使えてしまうのと同じですが、この概念については、更に後に数学で学ぶことになります。

 

 二進数の掛け算と割り算をする場合、加算器を使った処理をする方法もありますが、加算処理と同様にシフトレジスター回路を使った処理で計算をすることができます。この便利な仕様を桁が並んだ状態で処理をするのは難しいのですが、マイクラでも桁を一方向に移動させるだけだと比較的簡素な作りの回路で実装できます。

 

 

これとは別の方法で、リピーターロック機構を使う方法もありますが、桁数を挙動にそのまま割り当てると、

 

 

のようにデコーダーを使ってパターン制御をすることもできます。

 

 プログラムミングを行う場合にも、計算をする上でシフトレジストを行ったほうがいいので、桁の移動が行えます。

 

 フトと機能                      

 

 マイクラで回路を組む時には、双方向シフトレジスター回路があるとかなり便利ですが、この機能はプログラミング言語では標準実装されています。シフトという機能になりますが、左シフトと右シフトがあります。Pythonでもシフトは使用できますが、

 

■ 左シフト                        

 

   指定した桁数だけ左にずらして、空いた桁には0が入る

    

    演算子 : <<

  

 

■ 右シフト                        

 

   指定した桁数だけ右にずらして、空いた桁には0が入る

    

    演算子 : <<

 

 

を用いることで、二進数の桁を変更できます。

 

 

 シフトと演算                    

 

 Pythonで実際に左シフトを使ってみると、

 

 

のような感じになります。符号が付くとエラーが出る(右シフトを左シフトで行う事はできないようです。)ようになっていますが、整数をbin()関数でバイナリーにしても桁が動いていますし、二進数を使っても同様に動いています。

 

 このシフトレジストは二進数の世界だとかなり意味があるのですが、この挙動と筆算の挙動が一致しているので、二進数では、

 

【 左シフトの挙動は、掛け算の結果 】

 

になります。二進数では、桁が上がるごとに2倍になりますが、この特性は、1<<としたときに、 1 << 2 と同じになります。

 

 その為、

 

【 nビットの左シフト 】 = 【 2の掛け算 】

 

と同じ結果になります。筆算も左にシフトしますが、二進数の掛け算も左に数値をシフトして計算することで、

 

 

 シフトと演算                    

 

 右シフトは、右に桁が移動するので、桁が減少する処理になります。

 

これをPythonで実行してみると、

 

 

のようになります。これを見ると、桁が減っていますが、この処理は、割り算の挙動になります。その為、

 

【 nビットの右シフト 】 = 【 2の掛け算 】

 

(桁は切り捨てになります。) 

 

になります。筆算の割算でも桁が右にシフトしていきますが、同じような挙動がここにも存在しています。

 

 

 ットマスク                      

 

 ビット演算は色々と便利ですが、元の数値から指定した物だけを抽出する事が出来ます。例えば、10011001と言う数値があったとして、真ん中の11を抽出する場合、何をすればいいのか?を考えると、必要なのは、11ですから、0b11を判定の材料にして、0b10011001の中央の部分の0b11を取り出す事になります。この場合、桁数の多い数値から2桁を取り出すの柄、その抽出をする桁を合わせてANDで判定を行うと、11同士なので抽出ができます。その為、

 

 

のように右シフトで桁をずらしてANDで判定をすることで、抽出する事が出来ます。その為、 【 判定の条件 】 【 桁数 】 を決めておいて、その中の判定の場所を指定しておくと、その場所の状態を基準に判定を行う事が出来ます。つまり、 【 指定した複数のフラグを横並びに指定しておき。その桁のANDで判定を行った時に、TRUEの場合にのみ動作するような仕組み 】 を実装できます。

 

また、桁の追加も可能で、この場合には、左シフトを行う事で、下の桁を増やす事ができます。

 

 

 

 ットマスク(部分的な変更)           

 

 ビットマスクを使うと、値の置き換えもできます。この場合、ANDで消してORで追加することで、情報を変更できます。この時に、判定用の数値ですが、残す部分を1にして、消す部分を0にしてANDで合成すると、1を必ず残してくれるので、1で指定した部分は残ります。0の部分は元から何もないので、弾かれますから、もしも、入れえる場所に1があった場合に、1と0の組み合わせにして消せるように0を指定しておきます。

 

 そして、その消した部分にORで数値を入れると、1の情報を追加できるので、新規に情報を入れ替える事が出来ます。

 

 

このように、完全にデータをクリアにして、そこに新規のデータを挿入できるので、色々な場所で使えます。この状態を見ると、マスク処理と画像の差し替えと同じように感じる人も居るのではないかな?と思いますが、マスク処理を使った合成でも使用されています。

 

 

 ットマスク(異なる部分の抽出)        

 

 マスク処理では、クロマキーのように一致する部分を除去する処理がありますが、この場合、

 

     一 致  : 透過

     不一致 : 不透過

 

にする必要があります。そうなると、 【 不一致の検知 】 を行う必要があります。この場合、XORがその仕様になっていますから、XORで判定を行います。

 

 

こうすると、異なる部分だけが抽出されるので、その部分を使う事が出来ます。つまり、二値マスクを作ると、マスク部分とそうでない部分がしっかりと別れるので、その後にXORでマスクのカラーの一致の条件で抽出するとそれ以外の物が抽出されます。

 

 この条件で考えると、桁数を持たバイナリーに各フラグやアイテムのスロットを割り当てておいて、状態を指定する時の判定用に使う事もできるので、16進数で管理して、使用する時にバイナリーに戻してチェックを入れて使うという事もできます。

 

                               

 

 ビット演算は論理演算を指しますが、結構いろいろな事が出来ます。10進数の掛け算だと、ループ処理を行う事もできますが、2進数の場合だと、シフトレジストで掛け算と割り算ができます。

 

 これは二進数なのでレッドストーン回路でも使用できるのですが、実際に、ループ処理の物とシフトレジスト方式の物が存在しています。

 

 バイナリーは二進数なので、16進数に圧縮すると結構な桁数を格納できるので便利ですが、16進数の代入をして、バイナリーに戻して、使用すると0と1のフラグが用意した桁数分だけ存在するので、色々な管理ができます。この処理を、少ない文字列のデータの代入だけで出来るというのもバイナリーを使った場合(二進数と16進数を使った場合)のメリットになります。

 

 ちなみに、マイクラの回路を作る場合だと、シフトレジストは、桁の維持なので、4bitの10進数で使用できる形の値を記憶しなくてはなりませんから、一次記憶領域を作らないと数値は使えません。その為、コンピューターのプログラミング上ではそう言ったことができますが、アナログのデバイスで同様のことをトランジスタだけで行うとかなり巨大で複雑な物を作る事になります。