HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2016
1207
てんIF文と論理式の速度について18解決


てん

リンク

2016/12/7(Wed) 14:49:01|NO.77464

ゲーム等でキー入力によるキャラクターの移動に、
以下の①②のようなスクリプトが使われると思います。

これらについて、以下ご教示お願いします。

①ビットシフトによる理論式
mv=5
stick a,15,1
xv=(a>>2&1)-(a&1)
yv=(a>>3&1)-(a>>1&1)
px=xv*mv+px:py=yv*mv+py

②ベタなIF文
mv=5
stick a,15,1
if a&1:px-=mv
if a&2:py-=mv
if a&4:px+=mv
if a&8:py+=mv

これら2つは機能的には同じと思っていますが、どちらが速度的に有利でしょうか。
それぞれ5千回繰り返した場合の時間を求める様なスクリプトを教えて頂けますと幸いです。

BASIC等の時代では如何に速度が遅くなりがちなIF文を使わないかみたいな文化があったようですが、
もしHSPにおいて速度差が無ければ、無理にこねくり回した論理式を使うよりベタなIF文の方が
分かりやすいかな…と。。



この記事に返信する


窓月らら

リンク

2016/12/7(Wed) 17:48:43|NO.77468

簡易的ですが。

mes "wait..." wait 100 t1=time() repeat 2000000 mv=5 stick a,15,1 xv=(a>>2&1)-(a&1) yv=(a>>3&1)-(a>>1&1) px=xv*mv+px:py=yv*mv+py loop t2=time(): mes "論理式:"+(t2-t1) t1=time() repeat 2000000 mv=5 stick a,15,1 if a&1:px-=mv if a&2:py-=mv if a&4:px+=mv if a&8:py+=mv loop t2=time(): mes "IF文:"+(t2-t1) mes "ok" stop #defcfunc time return (gettime(6)*1000)+gettime(7)
この場合はifのが速そうですね。



KA

リンク

2016/12/7(Wed) 18:28:06|NO.77470

IFが遅いというよりも、気にしすぎて逆に演算回数を
増やしてしまった感じですね。



窓月らら

リンク

2016/12/7(Wed) 21:03:49|NO.77477

うちならこうするかなー。

mv=5 repeat stick a,0,1 px+=((a & %0100)-(a & %0001))*mv: py+=((a & %1000)-(a & %0010))*mv cls mes "px="+px+" py="+py await 16 loop


上の方法で比較。

mes "wait..." wait 100 mv=5 t1=time() repeat 2000000 stick a,0,1 px+=((a & %0100)-(a & %0001))*mv:py+=((a & %1000)-(a & %0010))*mv loop t2=time(): mes "論理式:"+(t2-t1) t1=time() repeat 2000000 stick a,0,1 if a&1:px-=mv if a&2:py-=mv if a&4:px+=mv if a&8:py+=mv loop t2=time(): mes "IF文:"+(t2-t1) mes "ok" stop #defcfunc time return (gettime(6)*1000)+gettime(7)


これでもifのが少し速いか。



窓月らら

リンク

2016/12/7(Wed) 21:27:10|NO.77478

うん、この場合はifでいいんじゃないですかねー。
ちなみに昔のBASICでは確かに論理式にしたほうが速いケースはありましたが、
あれは8bitなマシンでインタープリタな言語を走らせた場合にちょっと体感できる
くらいのもので、内容によってはIFのが速いケースもありました。
ケースバイケースで選択すればいいと思います。
(個人的には論理式を好んで使いますけど)



GENKI

リンク

2016/12/8(Thu) 01:07:43|NO.77488

経験上は差が無いので、間違いが起こりにくい方法で書いたほうがいいと思います。
そのほうがバグも起きにくいしプログラムの完成も早くなりますしね。プログラムの完成が速いということは新しい機能を追加する余裕ができるということでもあります。
また、後で見たときにコードの意味が読み取れるような書き方をしたほうがメンテもしやすくなります。
ということで個人的にはIF文を推奨します。

今のPCは速いですしね。



てん

リンク

2016/12/8(Thu) 02:17:58|NO.77491

窓月ららさま

速度比較スクリプトありがとうございます。
なるほど、if文の方が早いですね。
論理式も速度向上してて、シンプルで良いですね。
私も、論理式の方が何か「プログラム」って感じで好きですが、
皆さまのご忠告通り、無理せずif文にします^^;

ありがとうございました。



てん

リンク

2016/12/8(Thu) 02:18:35|NO.77492

解決



A

リンク

2016/12/8(Thu) 16:57:54|NO.77500

自分のPCでは、窓月らら氏(NO.77477)の
stick a,0,1

stick a,15,1
にして、カーソルキー全押しで計測すると論理式の方が速いようです。
IF文の方はキーが押された分だけ計算が増える為、速度が不安定です。
実際はウエイトをかけるので差は無いと思いますが…。



USER

リンク

2016/12/10(Sat) 09:24:56|NO.77539

ちょっと質問なのですが
xv=(a>>2&1)-(a&1)
yv=(a>>3&1)-(a>>1&1)

↑これは1と-1が欲しいわけですよね?
どうして1と-1が返るのかよくわからないのですが…



窓月らら

リンク

2016/12/10(Sat) 11:17:49|NO.77541

>Aさん
そうですねー、まぁ…誤差みたいな差なので気にするほどではないかと。

>USERさん

うちが書いたこれと比較してみてください。
px+=((a & %0100)-(a & %0001))*mv
py+=((a & %1000)-(a & %0010))*mv

これは以下でも同じです。
px+=((a & 4)-(a & 1))*mv
py+=((a & 8)-(a & 2))*mv

2進数 10進数
0001 1
0010 2
0100 4
1000 8

>>はビットシフトです。
例えば a>>3&1 なら変数aに入ってるビットを>>に3bitシフトしてから&1で評価。
仮にaが2進数で1000が入ってたら0001になるわけ。
(ただこの用途ではビットシフトする必要は無いですね。)

a=2: mes (a=2)
これを実行すると1(真)が表示されます。aが2以外なら0(偽)です。
論理演算の結果をそのまま利用してるわけです。



てん

リンク

2016/12/10(Sat) 13:58:21|NO.77544

なるほど、論理式は速度が安定するんですね。

カーソルキーが押されたところの判定ビット(どれも押さない0000~全押し1111)を
無理やり1ビット目にシフトさせて、それが1かどうかを「&1」で判定(真偽)する。。

あれれ・・・? そうだと思ったのですが、、

質問に質問を被せるようで、すみません。
以下のスクリプトは3種の式の結果は同じだと思っていたのですが、、
…どこか間違っていますでしょうか?

repeat
cls
stick a,15,1
mes "十字キー入力"
mes "x:y="+((a>>2&1)-(a&1))+":"+((a>>3&1)-(a>>1&1))
mes "x:y="+((a & %0100)-(a & %0001))+":"+((a & %1000)-(a & %0010))
mes "x:y="+((a & 4)-(a & 1))+":"+((a & 8)-(a & 2))
await 16
loop



USER

リンク

2016/12/10(Sat) 14:53:52|NO.77545

窓月ららさん、ありがとうございました。
呑み込めました。(^^)
てんさんのレスも参考になりました。
ありがとうございました。



てん

リンク

2016/12/10(Sat) 16:01:43|NO.77547

スレ汚しすみません。
どうも、ビット演算と論理演算をごっちゃにしていたようです。
使い分け方あるんですかね、、素直に「=」にすれば良いのかな。。

repeat
cls
stick a,15,1
mes "十字キー入力"
mes "x:y="+((a>>2&1)-(a&1))+":"+((a>>3&1)-(a>>1&1))
mes "x:y="+((a = %0100)-(a = %0001))+":"+((a = %1000)-(a = %0010))
mes "x:y="+((a = 4)-(a = 1))+":"+((a = 8)-(a = 2))
await 16
loop



A

リンク

2016/12/10(Sat) 21:20:25|NO.77554

一行目(窓月らら氏仕様)で良いと思います。

stick a,15,1
の場合、キーの複数押しを想定すると「a=0~15」になります。
IF文の「&」は「真=1=0以外」「偽=0」で処理できますが
論理式の「&」は「真=1」ではありません。

例えば「a=15」は
IF文では「if a&8 : ○○」で、○○処理できますが
論理式では「a&8」は「1」ではなく「8」なので計算がズレます。
また「a=8」とした場合は「0」になるので計算がズレます。

その為「a>>3&1」又は「(a&8)=8」で「1」を出す必要があります。

説明下手で、すみません。



窓月らら

リンク

2016/12/11(Sun) 03:59:07|NO.77560

すみませんポカミスしてました;
以下に修正します。

mv=5 repeat stick a,0,1 px+=((a=%0100)-(a=%0001))*mv: py+=((a=%1000)-(a=%0010))*mv cls mes "px="+px+" py="+py await 16 loop



窓月らら

リンク

2016/12/11(Sun) 04:25:49|NO.77561

あ、でも stick a,15,1 の場合は上のじゃ不都合だった。

mv=5 repeat stick a,15,1 px+=(((a&%0100)!0)-((a&%0001)!0))*mv: py+=(((a&%1000)!0)-((a&%0010)!0))*mv cls mes "px="+px+" py="+py await 16 loop


かえって面倒になったー。やっぱりこの場合はif文でよさそう。



窓月らら

リンク

2016/12/11(Sun) 04:42:31|NO.77562

ついでなのでベンチも更新しとくね。

mes "wait..." wait 100 mv=5 t1=time() repeat 2000000 stick a,15,1 px+=(((a&%0100)!0)-((a&%0001)!0))*mv: py+=(((a&%1000)!0)-((a&%0010)!0))*mv loop t2=time(): mes "論理式:"+(t2-t1) t1=time() repeat 2000000 stick a,15,1 if a&1:px-=mv if a&2:py-=mv if a&4:px+=mv if a&8:py+=mv loop t2=time(): mes "IF文:"+(t2-t1) mes "ok" stop #defcfunc time return (gettime(5)*60000)+(gettime(6)*1000)+gettime(7)


カーソルキー全押しだと px-=mv 等の処理が発生するのでifの負け。
何も押してないと論理式の勝ち。
でも200万回ループの結果ですから、誤差みたいなもんです。

大昔のBASICではこの誤差みたいな速度差が問題になることがあったので
速度を安定させる意味でも論理式にしていただけです。
(操作をしてるときだけ僅かに遅くなるので処理落ちしてるように感じる事があった)
今の環境(HSP)では余裕があって await でウエイトを入れてるわけですから
実用上はあまり気にする必要は無さそうです。



てん

リンク

2016/12/11(Sun) 06:37:25|NO.77563

ああ、なるほど、NOT取ればいいんですね。
論理式はやっぱり面白いですね。
色々勉強になりました、ありがとうございます。



ONION software Copyright 1997-2025(c) All rights reserved.