MUGENメモ ( フォント環境:MS ゴシック 標準 サイズ10 )  MUGENのための、ビット演算のメモ byADI 21:23 2010/07/16 修正 00:25 2010/03/30 --bit-- 12:41 2010/03/28 ちょこちょこ 12:02 2010/03/28 大きな桁の例 と bitの細かい解説など 22:00 2010/03/27 ちょこちょこ 21:26 2010/03/27 ちょこちょこ 17:58 2010/03/27 できた! できた? 13:18 2010/03/27 雑多メモ ( 参考:OG子 OGヲ@みすずLOVE様のキャラの記述 その他ググったビット演算子のページ )  ※このメモは、OG子 OGヲ@みすずLOVE様の記述を基本にして解説しています。  ※等幅フォント前提の表が多数存在します。 ■■■bit(ビット)演算とは?  数値のbitで演算を行うものです。  詳しく知らなくてもいい方は、0や1の大量に並んだ表までとばしてください。  ■bitとは?  ということを大雑把に説明すると、  >コンピューターは全て0と1の並びで情報を処理して、表示しています。  >その0,1の最小単位が1bitであり、数値情報もその0,1の2進法(bit)で行われています。  >例えば0〜7の数値をbitにすると、 000,001,010,011,100,101,110,111 という情報になり、   それぞれが 000=0,001=1,010=2,011=3,100=4,101=5,110=6,111=7 を表しています。  コンピューターの数値はそうした1と0だけの2進法で  1の1 10の2 100の4 1000の8 10000の16 100000の32 1000000の64 10000000の128  100000000の256 1000000000の512 10000000000の1024 100000000000の2048 1000,,,うんぬん   などを組み合わせることによって、膨大な数値を記録しているのです。  例えば 55 はbit数値だと110111になりますが、 # 0100000 32 # それは、:100000: 32 と # 0010000 16 # : 10000: 16 と # 0000100 4 # : 100: 4 と # 0000010 2 # : 10: 2 に # 0000001 1 # : 1: 1 をあわせた、 # 0110111 55 # ( 32+16+4+2+1 )の 55 を表しているということ。  ■で、bit演算とは?  bit演算とは、そのbit数値をくらべて処理を行う演算です。  ウィンドウズなら[電卓]を[表示]から[関数電卓]にすると   10進法←→2進法の確認ができる他、And Or Xor などのbit演算も可能です。  bit演算の6&3は2、5|6は7、3^5は6など、10進法だけで考えては全く分かりませんが、 ## 0110(6)& ## ## 0101(5)| ## ## 0011(3)^ ## ## 0011(3)= ## ## 0110(6)= ## ## 0101(5)= ## ## 0010(2), ## ## 0111(7), ## ## 0110(6), ##  こうした形で並べると、bitの数値に関係性が浮かんできます。  この法則で演算を行うのが、bit演算です。  ■bit性質について  通常の計算でbitの状態に注目すると、6-2=4は、 # ↓注目 # 6は右から2番目と3番目に1があって # 0110(6)- # 2は右から2番目にだけ1があり、 # 0010(2)= # 6の右から2番目の1を引いて、 # 0100(4) # 右から3番目にだけ1のある4にすることができます。  もっと大きな89-24などになっても、同じbitの桁に1のある数値を引くのであれば、 # ↓注目 # そのbitの桁にある1だけが0になった数値になります。 # 01011001 (89)- # bitを見ると89の 64(1000000)と16(10000)と8(1000)と1(1) から # 00011000 (24)= #  24の16(10000)と8(1000)を引いたので、 # 01000001 (65) #  64(1000000)と1(1)の65が残ったわけです。  ただし、そうした計算であればbitの配列が大きく崩れることはありませんが、 # ↓注目 # 24-2 など同じbitの桁に1のないところを引こうとすると # 011000 (24)- #  上にあるbitの数値を細かい数値に崩して数字を合わせるため、 # 000010 ( 2)= #  bitの配列が崩れてしまいます。 # 010110 (22) # 額の合う小銭が無いと、お札でおつりを貰うことになるわけです。  その他、プラス(加算)の場合は、マイナス(除算)で出した例とは反対に、 # ↓↓注目 # 同じbitの桁に1のある数値同士を足そうとすると1つ繰り上がり、 # 010110 (22)+ #  bitの配列が崩れてしまいます。 # 010011 (19)= # # 101001 (41) # まあ、プラスは滅多に使いませんが。  ■MUGENでは  Varの管理を行う際、より情報を詰め込むため、   bit演算を使ってbit単位にVarを管理することがあります。  Var(**)は32bitのInt型の数値で0,1が32個入っています。  [ 00000000000000000000000000000000 ]  この32個のbitを別々に管理することで、   より多くの情報を1つのVarに詰め込もうというわけです。  MUGENで使える演算子は&(and),|(or),^(xor)で、   これらを使い、Varを管理することになります。 ■■■ 演算子  ■ & and どちらも 両方が  1 & 1 = 1  & (and)は同じ桁が1同士であれば1に 1 & 0 = 0       同じ桁のどちらかが0だと0になります  0 & 0 = 0 例:6(0110) & 5(0101) = 4(0100)  ■ | or どちらかでも 片方でも  1 | 1 = 1  | (or)は同じ桁のどちらかでも1であれば1に  1 | 0 = 1      同じ桁が0同士だと0になります  0 | 0 = 0 例:6(0110) | 5(0101) = 7(0111)  ■ ^ xor どちらかだけ 片方だけ  1 ^ 1 = 0  ^ (xor)は同じ桁の片方だけが1であれば1に  1 ^ 0 = 1       同じ桁が0同士でも1同士でも0になります  0 ^ 0 = 0 例:6(0110) ^ 5(0101) = 3(0011) ## and ## or ## xor ##  ## 0110(6)& ## 0110(6)| ## 0110(6)^ ## 例の数値を、 ## 0101(5)= ## 0101(5)= ## 0101(5)= ##  縦に並べるとこのようになります。 ## 0100(4) ## 0111(7) ## 0011(3) ## ■■■ 32bit-Int型のbit数値(bit表)  この表の0や1を凝視しないようご注意ください。  0の数を数えたりすることなど、もっての他です。 10進法数値 : bit数値(2進法数値) (※もしかしたら打ち間違いあるかも) 桁数;21098765432109876543210987654321; 0 = 00000000000000000000000000000000 ;全て0 -1 = 11111111111111111111111111111111 ;全て1 2010032812 = 01110111110011101010101010101100 ;通常の数値 2147483647 = 01111111111111111111111111111111 ;最大値 桁数;21098765432109876543210987654321;桁数 -2147483648 = 10000000000000000000000000000000 32 (-2147483648 );最小値 1073741824 = 01000000000000000000000000000000 31 ( 1073741824 ) 536870912 = 00100000000000000000000000000000 30 ( 536870912 ) 268435456 = 00010000000000000000000000000000 29 ( 268435456 ) 134217728 = 00001000000000000000000000000000 28 ( 134217728 ) 67108864 = 00000100000000000000000000000000 27 ( 67108864 ) 33554432 = 00000010000000000000000000000000 26 ( 33554432 ) 16777216 = 00000001000000000000000000000000 25 ( 16777216 ) 8388608 = 00000000100000000000000000000000 24 ( 8388608 ) 4194304 = 00000000010000000000000000000000 23 ( 4194304 ) 2097152 = 00000000001000000000000000000000 22 ( 2097152 ) 1048576 = 00000000000100000000000000000000 21 ( 1048576 ) 524288 = 00000000000010000000000000000000 20 ( 524288 ) 262144 = 00000000000001000000000000000000 19 ( 262144 ) 131072 = 00000000000000100000000000000000 18 ( 131072 ) 65536 = 00000000000000010000000000000000 17 ( 65536 ) 32768 = 00000000000000001000000000000000 16 ( 32768 ) 16384 = 00000000000000000100000000000000 15 ( 16384 ) 8192 = 00000000000000000010000000000000 14 ( 8192 ) 4096 = 00000000000000000001000000000000 13 ( 4096 ) 2048 = 00000000000000000000100000000000 12 ( 2048 ) 1024 = 00000000000000000000010000000000 11 ( 1024 ) 512 = 00000000000000000000001000000000 10 ( 512 ) 256 = 00000000000000000000000100000000 9 ( 256 ) 128 = 00000000000000000000000010000000 8 ( 128 ) 64 = 00000000000000000000000001000000 7 ( 64 ) 32 = 00000000000000000000000000100000 6 ( 32 ) 16 = 00000000000000000000000000010000 5 ( 16 ) 8 = 00000000000000000000000000001000 4 ( 8 ) 4 = 00000000000000000000000000000100 3 ( 4 ) 2 = 00000000000000000000000000000010 2 ( 2 ) 1 = 00000000000000000000000000000001 1 ( 1 ) 0 = 00000000000000000000000000000000 桁数;21098765432109876543210987654321;桁数 ( 下で説明する【住所番号】や【基準数値】に使えます。 )  32桁目(マイナス側)の計算を自分で行ないたい場合、   31桁までのプラス数値を出して[ -2147483648 ]を加えて   計算すればできるかもしれませんが不安定かもしれませんので、  31桁までの使用が推奨かも。 ■■■ bitフラグ方式の利用  ※このメモは、OG子 OGヲ@みすずLOVE様の記述を基本にして解説しています。  ■代入の方法  まず上のbit表や電卓から「 bitで目的の桁だけが1の数値 」を割り出してメモしましょう。  それが、bitの目的の桁をON,OFFにする為の【住所番号】になります。アドレスナンバーです。  ONにする際は、Value = ( Var(**) | 【住所番号】 ) ;で代入。  OFFの場合は、 Value = ( Var(**) | 【住所番号】 ) - 【住所番号】 ;で代入。  つまり、ONには|(or)で空いていれば入れ、      OFFは |(or)で空いていれば入れてから外す、というわけです。  例・ONにしたい  00110000(48)の、bitの下から7番目を1にしたい場合は、( 48(00110000) | 64(01000000) )で、  01000000(64)の【住所番号】を|(or)で入れれば、  01110000(112)になり、下から7番目が1になります。   また、もし00110000(48)が01010000(80)で、元々7番目がONであっても、  01010000(80)に  01000000(64)の【住所番号】を|(or)をしても、  01010000(80)のままなので問題ありません。  例・OFFにしたい  00110110(54)の、bitの下から5番目を0にしたい場合は、( 54(00110110) | 16(00010000) ) - 16(00010000)  00010000(16)の【住所番号】を|(or)で入れても、  00110110(54)は既に5番目が1であるため変化はなく、そこから  00010000(16)の【住所番号】を引くことで、  00100110(38)になります。   それであれば、もし00110110(54)が01001010(74)で、元々5番目がOFFであっても、  01001010(74)に一度  00010000(16)の【住所番号】を|(or)で入れることで、  01011010(90)にしてしまい、そこからまた  00010000(16)の【住所番号】を引くため、  01001010(74)と元に戻り、5番目はOFFのままというわけです。  これらはとても高い数字であっても同様です。  下から25番目であれば( 00000001000000000000000000000000 ) 16777216 が【住所番号】に、  下から30番目であれば( 00100000000000000000000000000000 )536870912 が【住所番号】になるだけです。  しかし【住所番号】がbitで1なのが目的の桁でなかったり、   1が1つで無く複数あったりなど、不備があると不具合がでます。  ちなみに計算上は、Value = ( Var(**) & ( 【住所番号】 ^-1 ) )などでもOFFにできますが、   上記の方法の方が分かりやすいし信頼できるかと。  ^-1は、どちらかだけが1の時1になる^(xor)、bitが全て1の-1、それらを組み合わせたフラグ反転。  実際の反転数値を計算したい場合は、 ( 【住所番号】 +1 )*-1 でもフラグ反転の数値は割り出せます。  ■参照の方法  ONであるかOFFであるかは、 ( Var(**) & 【住所番号】 )で参照を行えます。  &を行う事で、その桁に1があるかどうかを判別でき、   無ければ0を、あれば【住所番号】の数値を返してくれる為、=は不可欠ではありません。  1か0の数値を返して欲しい場合は、    ( Var(**) & 【住所番号】 ) = 【住所番号】で、1かどうかの確認をでき   !( Var(**) & 【住所番号】 ) は目的の桁が0の時に1を返します。  !(!( Var(**) & 【住所番号】 ) )でも、1の時に1を返してくれます。  複数のフラグを参照したい場合は、一つ一つ別々に参照するか、  ( Var(**) & ( 【住所番号】 | 【住所番号】 | 【住所番号】 ) ) = ( 【住所番号】 | 【住所番号】 | 【住所番号】 )   という形で参照するか。もしくは最初から全て足した住所番号を使って&を行うかになります。  ■最低限■■■  bitで目的の桁だけが1の数値を【住所番号】としてメモしておき、  ONは、( Var(**) | 【住所番号】 )を代入すれば、【住所番号】で1にしたbitの桁が1になり、  OFFは ( Var(**) | 【住所番号】 ) - 【住所番号】 で代入すれば1にしたbitの桁が0になる、   ( Var(**) & 【住所番号】 ) であるかどうかを確認。  !( Var(**) & 【住所番号】 ) でないことを確認。   といったことだけを覚えれば、最低限使えるはずです。 ■■■数値を扱う bit分割方式  複数桁に渡って数値を管理することはできます。bitの法則を理解していれば簡単に理解できます。  ■方法  用意しておく数値( 表や関数電卓があると用意しやすい )   1.使用する桁の1桁目だけが1である数値の【基準数値】(出し入れするための「住所番号」)   2.使用する桁全てが1である数値の【範囲数値】(使う範囲を示す「所有地の情報」)    2−1.範囲数値を基準数値で割った限界値(入れられる数値の最大)   3.代入する情報の【代入数値】 基準数値の例: 256( 000000100000000 ) 範囲数値の例:7936( 001111100000000 ) 限界値:31( 11111 )  代入は「 Value = ( Var(**) | 【範囲数値】) - ( 【範囲数値】 ) + ( 【基準数値】 * 【代入数値】 ) 」   範囲数値で|と-を行って使用範囲を空にし、基準数値を掛けた代入数値を入れる形です。  参照は「 ( ( Var(**) & 【範囲数値】 ) / 【基準数値】 ) = 代入していた数値 」   範囲数値で&を行い使用範囲以外を空にし、基準数値で割って代入していた数値を参照します。  加算などの処理を行いたい場合は、限界値を超えてしまうと不具合が出るため、   限界値でないか確認を行うか、参照した数値に加算を行ったものを代入数値として代入しましょう。  また代入を行う際も代入数値が限界値を超えないように注意し、超えている場合代入してはいけません。   超えている分は補正などの対処をさせ、超えるような不定数値にはあまり使わないようにしましょう。  ■解説  と、いきなり方法を示しても、よく分からないと思いますので説明を。  例えば、xx * 2 (2倍)するとbit数値は1つずつ桁が上にずれます。  これはそれぞれの桁数が持っている数値の2倍が1桁上の数値であるため。  28( 11100 ( 16+8+4+0+0) ) を【*2】するとbitは0が1つ増えて、 56( 111000 (32+16+8+0+0+0) ) という状態になるというわけです。  では反対に / 2 をするとどうなるのか。  28( 11100 ( 16+8+4+0+0) ) に【/2】を行ってみると、 14( 1110 ( 8+4+2+0) ) bit数値は0が1つ減り、さらに【/2】を行うと 7( 111 ( 4+2+1) ) さらに0が減って0がなくなります。  これは、*2,/2だけでなく、その2倍やさらに2倍でも、 7( 111 ( 4+2+1) ) へ2倍の2倍の2倍(2の3乗)である8で、【*8】すれば、 56( 111000 (32+16+8+0+0+0) ) bit数値は0が3つ増える形になり、反対に【/8】をすれば、 7( 111 ( 4+2+1) ) の元に戻ります。  つまり、【基準数値】になる2の累乗数(bit表で桁数の書かれた数字のこと)で掛ければ、   そのbitの桁をその数値の「基準位置」にすることができるわけです。  こうした法則を利用することによって、bitの桁を分割し、   10bit分の数値情報を32bitの中に3つ入れることができます。  例えば、872,1008,1020という情報を通常Varに入れることは出来ませんが、  bitを[ ,,xxxxxxxxxxyyyyyyyyyyzzzzzzzzzz ]このように分けて考え、 ,,xxxxxxxxxxyyyyyyyyyyzzzzzzzzzz 【範囲数値】 00111111111100000000000000000000 x (1072693248) 00000000000011111111110000000000 y (1047552) 00000000000000000000001111111111 z (1023) =限界値 ,,xxxxxxxxxxyyyyyyyyyyzzzzzzzzzz 【基準数値】 00000000000100000000000000000000 x ( 1048576 ) 00000000000000000000010000000000 y ( 1024 ) 00000000000000000000000000000001 z ( 1 )   こうした【範囲数値】と【基準数値】を算出しておきます。   ,872をxに入れるならxの【基準数値】の 1048576 を掛けて、   1008をyに入れるならyの【基準数値】の 1024 を掛けて、   1020は、zの基準数値が1なのでそのまま、  x,110110100000000000000000000000 ( 914358272 )  y, 11111100000000000000 ( 1032192 )  z, 1111111100 ( 1020 )   この3つの数値を合わせることによって、( 914358272 | 1032192 | 1020 ) xyz,110110100011111100001111111100 ( 915391484 )   [ 915391484 ]の中に、3つの数値の情報を入れることができてしまいます。 ( |はbitに1の重複する桁が無ければ、+したのと同じ数値になります。 )  そして、[ 915391484 ]から、先ほどの872,1008,1020を取り出したい場合、  xであれば、xの【範囲数値】で&を行い、xの【基準数値】を割れば、  ( 915391484 & 1072693248 ) / 1048576 ;で、872を取り出すことができます。  yであれば、xと同じようにyの【範囲数値】で&を行い、yの【基準数値】で割れば、  ( 1032192 & 1047552 ) / 1024 ;で1008を取り出すことが出来ます。  zならば、zの【範囲数値】で&を行うだけで、  ( 915391484 & 1023 ) ;1020を取り出すことができるというわけです。  ちなみに、ウィンドウズの関数電卓であれば、これらのbit演算の確認も出来ます。  ただし、こうしてまで1023を3つ管理しても、   999まで出来る10進法の桁分割方式と大差はありませんが。  ■限界値に補正する方法 Trigger1 = ( 代入数値 <= 限界値 );代入の条件にはこちらを入れ、  限界値を超えるような情報を入れさせないようにし、 Trigger1 = ( 代入数値 > 限界値 ) ;こちらの条件で補正数値を代入させます。  限界値をそのまま入れるなり、エラーフラグを立てるなり。  ただしこれらも、あまり好ましい方法ではありませんので、   一定までの数値や小さめの数値に限定したり、   大きな数値を扱う場合には大きめに範囲を取っておきましょう。  ■ちなみに  bit演算に頼らずbitの桁がどうなっているか調べたい場合は、   確認したい【住所番号】で数値を割り、1の位が奇数か偶数かを確認すれば   【住所番号】の桁が1(奇数)か0(偶数)か、確認できます。  ※計算できれば、ですが。高い桁数だと、卓上電卓では桁数が足りません。PC電卓などなら大体できますが。 ★特定の【住所番号】より低い桁数は全て1であっても1以上にならない  >例えば「001000」の8より低い桁数が全て1でも「000111」の7にしかならず、   7/8では0.875と1未満なわけです。31桁目が1÷30桁目まで1だと   「0.999999999068677425384521484375」と9が9個並びつつも、1未満です。 ★特定の【住所番号】より高い桁数は全て指定【住所番号】の2の累乗数である。  >例えば「001000」の8より高い「010000」の16や「100000」の32はいずれも8より高い2の累乗数です。   元々bitは一つ桁が上がることに2倍になるので、当然の仕組みですが。  この2つの法則があるため、特定の【住所番号】で割れば、1の位の数字で   その【住所番号】のbit桁数が1(奇数)か0(偶数)か確認できるわけです。 ■■■実際に使う場合  しっかりと何の桁に何を使っているのかに加え、   ここで言う基準数値なども一緒にメモしておきましょう。  また本当にbit形式でやるべきかどうかも考慮しましょう。  よく例を出しますが、0〜4までの数値と5のスイッチを9個使いたい場合、   bitでは一桁の数値に3bit(0~7)、スイッチにも1bit必要になり、   それが9個となると36bitも必要になり、bit方式では数値が足りません。  勿論その方式は酷く手間が掛かりますけど。  ※このメモは、OG子 OGヲ@みすずLOVE様の記述を基本にして解説しています。 ;Var表用の31bit分割表 住所番号付き ;Var(**)1 =(1) = ;--bit--2 =(2) = ;--bit--3 =(4) = ;--bit--4 =(8) = ;--bit--5 =(16) = ;--bit--6 =(32) = ;--bit--7 =(64) = ;--bit--8 =(128) = ;--bit--9 =(256) = ;--bit-10 =(512) = ;--bit-11 =(1024) = ;--bit-12 =(2048) = ;--bit-13 =(4096) = ;--bit-14 =(8192) = ;--bit-15 =(16384) = ;--bit-16 =(32768) = ;--bit-17 =(65536) = ;--bit-18 =(131072) = ;--bit-19 =(262144) = ;--bit-20 =(524288) = ;--bit-21 =(1048576) = ;--bit-22 =(2097152) = ;--bit-23 =(4194304) = ;--bit-24 =(8388608) = ;--bit-25 =(16777216) = ;--bit-26 =(33554432) = ;--bit-27 =(67108864) = ;--bit-28 =(134217728) = ;--bit-29 =(268435456) = ;--bit-30 =(536870912) = ;--bit-31 =(1073741824)= ;