トピック
kurono64 kazuki327

FOR,UNTIL,WHILEループ速度について

FOR,UNTIL,WHILEそれぞれのループの速度を計りましたが(旧3DS)、ループの時に使用するのにどれが一番使った方がいいのかよく分からないので教えて欲しいです。
2そうだね
プレイ済み
返信[1]
親投稿
kurono64 kazuki327
【追記】 一応、ラベルのループも計測してみました。
0そうだね
プレイ済み
返信[2]
親投稿
だにえる haru2016nen
個人のセンスの違いもあるけど、 それぞれの要素に合った使い分けを すればいい。 UNITLが最速じゃなかったっけ
4そうだね
プレイ済み
返信[3]
親投稿
だにえる haru2016nen
要素→用途 例えば WHILE !(BUTTON(2)==#A) VSYNC:WEND と RRPERT:VSYNC UNITIL BUTTON(2)==#A ボタンが押されるまで止まるってやつ。 ボタン情報はフレーム毎に更新されるので 前者はRUN命令でプログラムを実行した とき(直後)などに反応しなく なってしまいます。 VSYNCをはさんでいないので。
0そうだね
プレイ済み
返信[4]
親投稿
特殊な場合の速度優先を除き、基本は適材適所。
2そうだね
プレイ済み
返信[5]
親投稿
おちゃめ ochame_nako
New3DS LLを使ってループにかかる時間を計測してみました。  ☆計測条件☆ ・1000万回ちょうどでループが終了する ・プログラムは最速となる書き方で記述 ・ループプログラムはプログラムスロット0の先頭に記述 ・MILLISECを用いて3回計測してその真ん中の時間を採用 GOTO@ラベル 5395ms FOR~NEXT 6696ms WHILE~WEND 5881ms REPEAT~UNTIL 5419ms というわけで速度だけを見ればGOTOが最速です。(±20msくらいの誤差はある) しかし、これは微々たる差でありこの速度差が重要になることはほとんどないため速度よりも自分の用途に合ったものを選択すると良いでしょう。
1そうだね
プレイ済み
返信[6]
親投稿
おちゃめ ochame_nako
(続き) GOTOの一番のメリットはジャンプ先が自由ということです。 それは逆に言えばGOTOとラベルが1対1で対応しなくても問題ないためスパゲッティになりやすいとか視認性も悪くなるというデメリットにもつながっています。(他のループ命令では開始命令と終了命令が1対1で対応している) FOR~NEXTは一定回数繰り返すプログラムや特定の変数の値を一定ずつ変化させるプログラムを作りやすいです。 必ずカウンタ変数が必要なのでそれが必要のない場合はWHILE~WENDかREPEAT~UNTILを選んだ方がベターです。(他のループ命令はカウンター変数無しでもループ可能なので単にループを繰り返すだけならば上記の中でFOR~NEXTとの差はさらに開く)
3そうだね
プレイ済み
返信[7]
親投稿
おちゃめ ochame_nako
(続き) WHILE~WENDとREPEAT~UNTILは条件付きのループを作りやすいです。 WHILE~WENDは入り口チェックであるためループ開始時に条件を満たしてないと1回もループ内を実行せずスキップされますがREPEAT~UNTILは出口チェックであるため最低1回はループ内を実行します。 ただし、WHILE 1~WENDと記述してBREAKで抜ければループ内を確実に実行させることは可能なのでそこまで入り口、出口に拘らなくても良いです。 使い分けるのが難しければどれか1つを確実に使えるようになれば問題ありません。 個人的にオススメはWHILE~WENDです。 「FOR~NEXT的な用途、REPEAT~UNTIL的な用途に対応可能」「タイプしやすい」かつ「速度もそこそこ速い」ためです。
1そうだね
プレイ済み
返信[8]
親投稿
おちゃめ ochame_nako
だにえるさんへ 一般的な書き方ではREPEAT~UNTILが最速ですが、最速の書き方では実はGOTOが最速です。 「GOTOはあくまで分岐命令でありループ命令ではない」となればほぼあらゆる条件下でREPEAT~UNTILが最速になります。 ちなみに私がオススメしたいAボタン待ちプログラムはこれです。 REPEAT  WAIT UNTIL BUTTON(2)==#A ですね。 VSYNCは前回のVSYNCからの経過時間待つ命令なので場合によってはVSYNCがキャンセルされAボタンを押すまで待ってくれず誤動作の可能性があります。 開始時にRUN+Aボタンでスタートする等の特定条件下のみに起こることですが。
1そうだね
プレイ済み
返信[9]
親投稿
おちゃめ ochame_nako
ちなみに上記の1000万回ループを最速の記述ではなく一般的な記述で計測したらこのようになりました。 GOTO@ラベル 6725ms(+1330ms) FOR~NEXT 6998ms(+302ms) WHILE~WEND 6728ms(+847ms) REPEAT~UNTIL 6156ms(+737ms) 単純なループだけでも記述方法によってこれくらいの差はでます。 これが複雑なプログラムであれば桁違いの差になるので速度が必要なプログラムはループ命令の微々たる速度差を考えるよりもアルゴリズムを変える等で高速化した方が良いです。
1そうだね
プレイ済み
返信[10]
親投稿
kurono64 kazuki327
丁寧に分かりやすく教えていただき、ありがとうございます。 ループの種類よりもループ内の処理が重要なのですね。
0そうだね
プレイ済み
返信[11]
親投稿
なんか前、激遅四天王なんかでGOTO文が入っていたような……
0そうだね
プレイ済み
返信[12]
親投稿
おちゃめ ochame_nako
クロノさんへ 本当に限界まで高速化するならばループ自体の高速化も必要ですが、大抵の場合はループよりもその中の処理の方が遙かに高速化の余地があるということです。 アルゴリズム以前にループ内にある乗算を除算に変えるだけでもループ自体の速度差以上の高速化が可能なレベルです。 それを行った上でさらなる高速化としてループ自体の高速化を行うならば問題はありません。 しかし、ループの速度を気にする人ならば乗算を使ってはいけません(笑) まして、速度を気にしている人が加算の代わりにINCを使うなんて言語道断です。(インクリメント専用の演算子が遅いのはプチコン3号、BIGだけであって他の環境ならばあり得ないこと) そこまで速度を気にしないならば自分が使いやすいものを使えば良いですよ。 場合によってはループ回数を桁違いに減らせることもあります。 ソート処理を作っていればその差はよく分かると思います。
1そうだね
プレイ済み
返信[13]
親投稿
おちゃめ ochame_nako
オワたず(^p^)ゝさんへ これが激遅四天王だ!! ・関数より遅い配列! ・除算より遅い乗算! ・加算より遅い inc! ・repeat until より遅い goto! (※MIKIさんのコメントからコピペ) MIKIさんが挙げている激遅四天王は相対的に見ておかしいくらい遅いものです。 四天王の一角である「乗算」が遅いといっても三角関数より遅いなんてことはなく除算よりも乗算の方が明らかに遅い(例えば、4を掛けるより0.25で割った方が速い)から激遅四天王に認定されているわけです。 他の環境でもREPEAT~UNTILよりもGOTOによる分岐の方が遅いなんてことはないですからね。 私の最速記述でようやくギリギリ逆転したというレベルです。
3そうだね
プレイ済み
返信[14]
親投稿
はる HARUHI-0913
↑じゃあいつもコロンを使わない自分は正解ということですね。参考になります。 ループ命令だったらREPEAT~UNTILが一番速いそうです。 後、関係無いですが、 文字列変数から1文字抜き出す時は、 MID$(文字列変数,位置,1) よりも 文字列変数[位置] の方が速いそうです。
3そうだね
プレイ済み
返信[15]
親投稿
MIKI ifconfig
BlackSoftさん > 文を繋ぐコロン「:」も実行速度にある程度影響する それは不思議ですね。 具体例を出してください。
0そうだね
プレイ済み
返信[16]
親投稿
MIKI ifconfig
inc「gotoがやられたようだな…」 乗算「ククク…奴は四天王の中でも最弱…」 配列「repeatごときに負けるとは激遅族の面汚しよ…」
4そうだね
プレイ済み
返信[17]
親投稿
BlackSoft BlackSoft.mkII3g
> 文を繋ぐコロン「:」も実行速度にある程度影響する 上記のソースコードを実行した結果、処理速度に全く差はありませんでした。 mkIIでは差が出ていたので、3号でも…と思い込んでいましたが、改善されているんですね。 確証なしで投稿してしまいすみませんでした。 上記の投稿は削除させていただきました。
1そうだね
プレイ済み
返信[18]
親投稿
おちゃめ ochame_nako
BlackSoftさんへ プチコンmkIIではコロンどころかスペースでも1個あたり60ナノ秒くらいの処理時間がかかっていましたね。 これはインタープリタ方式だと当たり前のことで高速化を追求したプログラムでは古くから余分なスペースやコロンや改行を無くすというのが常套手段でした。 プチコン3号では実行時に仮想マシンコードへと変換されます。要するに構文チェックと中間コードへの変換が実行した時点で終わっているためスペースやコロンによる速度低下は理論上起きることはないのです。
4そうだね
プレイ済み
返信[19]
親投稿
MIKI ifconfig
BlackSoftさん 検証ありがとうございます。おちゃめさんご指摘の通り、生成される内部コードが同じであればコロンの有無に関わらず実行時間に差はないと思われます。 プチコン3号では実行ステップ数(実行時間に直結する)は、 ・変数名で+2,定数で+1,関数で+1,演算子で+1 くらいと想像しています。厳密ではないけど、おおざっぱな目安にはなります。 参照: https://miiverse.nintendo.net/posts/AYMHAAADAAB2V0fPso64pw 例えば mid$(a$,i,1) => 関数,変数,変数,定数 => 1+2+2+1 = 6 a$[i] => 変数,変数 => 2+2 = 4 なので後者が速いって感じ。 あくまでもおおざっぱな目安ですよ。
2そうだね
プレイ済み
返信[20]
親投稿
MIKI ifconfig
あと、文字列の連結(a$=a$+b$)は a$ が長くなるとものすごく遅くなります。ほんとにいやになるくらい。長さの二乗に比例しておそくなると考えていい。 inc の持つ副作用を理解した上で、可能であれば inc a$,b$ を使いましょう。 prgset も基本的に文字列の連結になってるらしいです。何度も何度も何度も何度も prgset するよりは、変数に inc しておいて、一気に prgset した方が圧倒的に速くなります。 私はデバッグ用に prgset を多用していますが、行数が増えるにつれて目に見えて実行速度が落ちるのをしょっちゅう体感しています。
3そうだね
プレイ済み