hinekure.net が http://hspdev-wiki.net/ から自動クローリングした結果を表示しています。画像やリソースなどのリンクが切れています。予めご了承ください。 |
HSP2.61
|
ビット操作を覚えると効率良くスクリプトが書けるようになったりします。
$で始まる数値->16進数 $00は8bitで0 $0001は16bitで1 $000000FFは32bitで255 いずれも内部表現は32bitに変わりない。
%で始まる数値->2進数 %1000は4bitで8 %10000000は8bitで128 %%11111111111111111111111111111111は32bitで-1 いずれも内部表現は32bitに変わりない。
10進数で表現するよりも分かりやすい場合や、数値が何バイト(何bit)なのかを強調したい時などに使ったりします。
1100 0011 &)0000 1111 ----------- 0000 0011
1 2 3 4 |
|
0000 1111 0000 1111 0000 1111 0000 1111 &)0000 0001 &)0000 0010 &)0000 0100 &)0000 1000 ----------- ----------- ----------- ----------- 0000 0001 0000 0010 0000 0100 0000 1000特定のビットを抜き出す*1時に使ったりします。
1100 0011 |)0000 1111 ----------- 1100 1111
1 |
|
0000 0001 |)0000 0010 |)0000 0100 |)0000 1000 ----------- 0000 1111特定のビットをたてる*2時に使ったりします。
1100 0011 ^)0000 1111 ----------- 1100 1100 ^)0000 1111 ----------- 1100 0011
value>>n ;数値のビットを右にnビットずらす value<<n ;数値のビットを左にnビットずらす
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
関連ページ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
APIを使うようになると色関係の値はRGB単独で返ってくるわけではなく、1つの32ビット数値として返ってくるものが多い。
32ビット数値には次に示す
1〜 8ビットにR要素 9〜16ビットにG要素 17〜24ビットにB要素
というように各要素が格納されている。
これを取り出す方法として一番簡単なのはビットシフト(>>)とビットマスク(&)を使うことだと思う。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
HSP予約のcolor命令はRGB要素を独立して指定しますので、ここでは色を表す32ビット数値を指定して現在色として設定するモジュール仕立てにしてみました。
命令名もcolor32。いい感じですか?(Win32 APIの32に合わせて・・・)
実行すると『黒→赤→緑(黄緑)→青』と2秒置きに背景が変わります。
色情報に使用されるのは下位24ビットなので、上位8ビットはどんな値でも影響ありません。
逆にHSPからAPIに色情報を与えたい場合でもAPIは色情報を受け取る引数を1つしか用意していないものもあります。
そういった時は上の取り出す手順の逆を行います。
1 2 3 |
|
のようにします。or演算子は+演算子でもいいと思います。
ここでRGB要素に分解する時には『& $FF』があったものが、32ビット値にまとめる時にはand演算子がなくなっています。
その理由は・・・ビットの補完を見てください。
できました。 -- kz3
ソースを載せるにあたっていろいろ調整していてUPが遅れてしまいました。
特定のビットをONにするのにはor演算子を使いますが、特定のビットをオフにするのにxor演算子は使えません。
対象となるビット列をtarget、オフにするビットを表したビット列をptn(patternの略)とした時、ptnを用いてtargetの特定ビットをオフにする式は
(target^(ptn^$FFFFFFFF))&ptn|(ptn^$FFFFFFFF)^(target^(ptn^$FFFFFFFF))
となります。(自分で考えついた方法。他にもっと短い式があるだろうか?) → もっと短い式は後半に掲載してあります。
分かりやすくしたソースを載せます。また、ビット列表示モジュールも作ってみました。
+ | bitoff[sp].as |
bitoff[sp].as
|
既にOFFになっているビットはOFFのままです。
これがxor演算子を使うと、0xor1=1になってしまいビットが立ってしまいます。
ファイル名から分かるとおり、このファイルはタブスペコンバーター?でインデントを整形しています^^(話が横に反れました。)
bitoffモジュール内の処理を図にしてみました。
+ | 処理内容 |
<point> <method> target = 0b11000011 00000010 <-pattern ---------------+ pattern = 0b00000010 xor) 11111111 | -------------------- ------------- | * 11111101 <-reverse_pattern ----+ | anser = 0b11000001 xor) 11000011 <-target | | ------------- | | 00111110 <-reverse_xor_target -)---)---+ & ) 00000010 <-pattern ------------)---+ | ------------- | | 00000010 | | | ) 11111101 <-reverse_pattern ----+ | ------------- | 11111111 | xor) 00111110 <-reverse_xor_target ---------+ ------------- ans> 11000001 |
もっと効率のいいアルゴリズムがあったら是非載せてください。
c = a and b xor aaが対象値、bでoffにする場所を指定する。
c = a&b^a
+ | サンプルスクリプト |
|
result = pattern ^ $FFFFFFFF & target
$FFFFFFFFとxorをとることによってpatternを反転し、targetと
andをとれば、patternが1のビットのみクリアされます。
Cのようにビット反転演算子が使えれば、さらに簡単になるのですが……。
xor演算子は潜在的に暗号化・複合化として機能しますが、これを利用して2つの値を交換するというスワップに使えます。
1 2 3 4 5 6 7 |
|
3行目はaをbというキーで暗号化したと捕らえられますが、同時にbはaというキーで暗号化したとも捕らえられます。
つまりこの演算から得られる値は両者の復号データと見なせます。
この復号データに暗号化時のキーをxorすると元データが得られます。(排他的論理和参照)
つまりbをキーとすればaが得られ、aをキーとすればbが得られるというわけです。
1 2 3 4 5 |
|
-15 = 11111111 11111111 11111111 11110001 wpoke 11111111 11110001 = 65521 wpeek 11111111 11110001 <<16 11111111 11110001 00000000 00000000 >>16 11111111 11111111 11111111 11110001 = -15
wpokeで書き込んだ値をwpeekで読み込むと負の値を書き込もうが 0 〜 65535 が値として戻ってきますが、
シフト演算子を使うと -32768 〜 32767 までの値を取り出すことが出来ます。
>>16をすると元の値に戻りそうですが符号付の場合は最上位ビットがコピーされます。
これを、算術シフトと言うそうです。
では実際に使ってみましょう。ということで。
1 2 3 |
|
これを実行すると
ok
と表示されました。
n&4
は、条件式ではないのに…なぜでしょう?
ちなみに 5は、
(4×1) + (2×0) + (1×1) = 5
です。この辺の詳しいことはビット操作をご覧下さい。
どうやら ifでは条件式の結果が 0でないときは条件が満たされたと判断し、 0のときは条件が満たされたものと判断するようです。
条件式には以下のようなものがあります。
記号 | 意味 | 記号 | 意味 |
= | 同じ | == | 同じ |
< | より小さい | <= | 以下 |
> | より大きい | >= | 以上 |
! | 同じでない | != | 同じでない |
if文の条件式にはこの他にも論理演算子などが使われることがあります。
ではこの辺でこれらの条件式の演算子を使用するとどうなるか確認しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
条件式が式が満たされるとき(真) | 1 |
条件式が式が満たされないとき(偽) | 0 |
n&4は 3番目のステートを取り出しているだけです。
n&4=4は、3番目のステートを取り出し、それが 4であるか?を調べています。
1 2 3 |
|
マニュアルではifのパラメータはp1は条件式となっているので、ここは
n&4=4
とするほうが正式な方法なのだと思われます。ただ、
n&4
と記述してもn=5のとき 0以外(この場合4)が返され真(式を満たす)と判断されるため問題はありません。
もしn=9であった場合 0が返されるため、偽(式を満たさない)と判断されます。
というわけでこのような記述ができるというわけです。
a=1 : b=1 if (a=1)&(b=1) : mes "ok" stop
このような場合も実際にやっているのは論理積ですので、同様の手順で考えることが出来ます。
ここでやっているのは、というより、HSPの論理演算は、ビット単位の論理演算であり、
論理演算とは区別する考え方が支配的です。
このあたりを理解しないで
if (key&4)&(enemy=1)
としてしまい、なぜ動かないのかと掲示板に投稿する例がときどき見られます。
昔のBASICでは、真を意味する値が1ではなく-1だったので、この判定でうまくいっていたのですが……。
JavaやC#など、真・偽を数値として処理することを許さないのが最近の傾向のようです。
CにもHSPにも昔のBASICにも真の定義が2つあるので、ある意味便利だけれど、
逆に混乱の原因にもなっているという反省から生まれた傾向でしょう。
HSPの論理演算を正しく理解していないと陥ってしまいやすいミスのパターンがあります。
stick命令を例にとってミスの例と解決策を見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
|