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


HSPTV!掲示板


未解決 解決 停止 削除要請

2021
0813
Y_repeatswitch分岐をリファクタするか思案中です8解決


Y_repeat

リンク

2021/8/13(Fri) 21:45:14|NO.93566

こんばんわ。
自分は現在プロコンに向けて
スタック式計算機CUI版みたいのを作成しています
まあインタプリタのやさしい書式の最初の方のプログラムの改造みたいかんじです
とはいえベースはMITライセンスのwhitespace言語ということにしてます

で、switchで入力とコマンドを比較してて
最初は!から始まる。つけなくてもよいというルールで
半分は!から始まる文字列と比較しています

ということはswitchではなくifで分岐すると比較の回数は半分になります
しかし半分だとswitch hogeとするとhogeは一回読むだけで
後は使い回すイメージでif分岐の後の比較は2回読みます
しかしそのうち一回はプログラム実行時にプログラムに読み込んで
文字列はメモリ上にありそうです

そしてswitchは毎回文字列比較しますがifで分岐すると
文字列比較の回数は!で比較した後なので半分です
ただ文字列比較はほぼ最初の3文字以下な気がします

という訳で
まあ、ざっくり言うと
switchで文字列比較を行っていて
!と比較した後比較すると比較回数が半分になりそうなんですが
速度的に改善しそうなものなんすか?
スクリプト的にはswitchで比較した方がわかりやすいので
そんなに速くならないならswitchで比較したいかんじです

テストケースも上手く洗い出せなくて
いまいち速度計測の形に持っていくようにイメージ出来ないかんじです



この記事に返信する


Y_repeat

リンク

2021/8/15(Sun) 16:49:54|NO.93584

こんにちわ。たぶんここに書き込んで頭が整理されたっぽく
要するに各処理を省いて 分岐とme少々を繰り返して計測すればいいという結論です
計測はググってここのサンプルスクリプトを使用しました
ありがとうございました



Y_repeat

リンク

2021/8/15(Sun) 16:54:37|NO.93587

資料として

#runtime "hsp3cl" #uselib "Kernel32.dll" #cfunc GetTickCount "GetTickCount" *START Ts=GetTickCount() memory = 0 str4input = "" int4input = 0 // TEST用文字列 // 入力ミスすることも考慮し無効な文字列も混ぜてます sdim commands,30,30 commands.0 = "123","456","789","1_23","add","!add","a-d-d","!A-D-D","discard","!discard","-987","-654","-123","-1_23","SUB","!SUB","S*U*B","!S-U-B","disc","!disc","" do_count = 0 commands_count = 0 commands_max =20 *begin do_count++ commands_count = do_count \ 20 if do_count >200{ T=GetTickCount()-Ts print T stop } //logmes "" + do_count + ":" + commands_count str4input = commands.commands_count //////////////////////////////////////// _1st_ch = peek(str4input,0) if _1st_ch == '0' || _1st_ch >= '1'{ if _1st_ch <= '9' { goto *begin } } _2nd_ch = peek(str4input,1) if _1st_ch == '-'{ if _2nd_ch == '0' || _2nd_ch >= '1'{ if _2nd_ch <= '9' { goto *begin } } } //////////////////////////////////////// switch str4input case "stack_discard": case "!stack_discard": case "STACK_DISCARD": case "!STACK_DISCARD": case "discard": case "!discard": case "DISCARD": case "!DISCARD": case "Discard": case "!Discard": mes "!DISCARD\n" goto *begin swbreak //////////////////////////////////////// case "!+": case "+":case "add": case "!add": case "ADD": case "!ADD": case "Add": case "!Add": mes "!ADD(!+)\n" goto *begin swbreak case "!-": case "-": case "sub": case "!sub": case "SUB": case "!SUB": case "Sub": case "!Sub": mes "!SUB(!-)\n" goto *begin swbreak swend mes "Pardon?\n" goto *begin



Y_repeat

リンク

2021/8/15(Sun) 16:55:26|NO.93588


#runtime "hsp3cl" #uselib "Kernel32.dll" #cfunc GetTickCount "GetTickCount" *START Ts=GetTickCount() memory = 0 str4input = "" int4input = 0 // TEST用文字列 // 入力ミスすることも考慮し無効な文字列も混ぜてます sdim commands,30,30 commands.0 = "123","456","789","1_23","add","!add","a-d-d","!A-D-D","discard","!discard","-987","-654","-123","-1_23","SUB","!SUB","S*U*B","!S-U-B","disc","!disc","" do_count = 0 commands_count = 0 commands_max =20 *begin do_count++ commands_count = do_count \ 20 if do_count >200{ T=GetTickCount()-Ts print T stop } //logmes "" + do_count + ":" + commands_count str4input = commands.commands_count //////////////////////////////////////// _1st_ch = peek(str4input,0) if _1st_ch == '0' || _1st_ch >= '1'{ if _1st_ch <= '9' { goto *begin } } _2nd_ch = peek(str4input,1) if _1st_ch == '-'{ if _2nd_ch == '0' || _2nd_ch >= '1'{ if _2nd_ch <= '9' { goto *begin } } } //////////////////////////////////////// /* _1st_char = strmid(str4input, 0, 1) flag_str_hit = 0 if _1st_char == "!"{ if _1st_char == "!bye" || _1st_char == "!BYE" : flag_str_hit = 1 }else{ if _1st_char == "bye" || _1st_char == "BYE" : flag_str_hit = 1 } if flag_str_hit == 1{ mes "bye" input str4input,2048,1 end }*/ _1st_char = strmid(str4input, 0, 1) flag_str_hit = 0 if _1st_char == "!"{ if _1st_char == "!stack_discard" || _1st_char == "!STACK_DISCARD" || _1st_char == "!discard" || _1st_char == "!DISCRAD" || _1st_char == "!Discard" : flag_str_hit = 1 }else{ if _1st_char == "stack_discard" || _1st_char == "STACK_DISCARD" || _1st_char == "discard" || _1st_char == "DISCRAD" || _1st_char == "Discard" : flag_str_hit = 1 } if flag_str_hit == 1{ mes "!DISCARD\n" goto *begin } flag_str_hit = 0 _1st_char = strmid(str4input, 0, 1) flag_str_hit = 0 if _1st_char == "!"{ if _1st_char == "!+" || _1st_char == "!add" || _1st_char == "!ADD" || _1st_char == "!Add" : flag_str_hit = 1 }else{ if _1st_char == "+" || _1st_char == "add" || _1st_char == "ADD" || _1st_char == "Add" : flag_str_hit = 1 } if flag_str_hit == 1{ mes "!ADD(!+)\n" goto *begin } flag_str_hit = 0 _1st_char = strmid(str4input, 0, 1) flag_str_hit = 0 if _1st_char == "!"{ if _1st_char == "!-" || _1st_char == "!sub" || _1st_char == "!SUB" || _1st_char == "!Sub" : flag_str_hit = 1 }else{ if _1st_char == "-" || _1st_char == "sub" || _1st_char == "SUB" || _1st_char == "Sub" : flag_str_hit = 1 } if flag_str_hit == 1{ mes "!SUB(!+)\n" goto *begin } flag_str_hit = 0 mes "Pardon?\n" goto *begin



Y_repeat

リンク

2021/8/15(Sun) 16:56:56|NO.93589

なんか毎回増減し同じスクリプトにしなきゃだめっすかね
どっちにしろあんまり変わらないという結論ぽいです



Y_repeat

リンク

2021/8/16(Mon) 18:16:03|NO.93598

こんばんわ。
レジスタには載せてないとしても
比較前にキャッシュに入れそうっすね

switchでキャッシュにいれて
キャッシュに入ってるのとメモリに入ってるののと

メモリとメモリのの演算かもなので

swicthはifの二倍くらい速いかもしれません

後、余計な演算多いので
特に問題のない速さって事かもしれません

自分、年単位でものすごい前
簡単なシナリオ解析プログラムを書きましたが
文字列の比較が多くてもやっとした速度でw

Winタブレットで遅い方だと思うんですけど
1.何GHzのデュアルコアっぽいです
Windowsの占有ぐあいも低いかんじします
要するに当時より速いとw

比較の命令数は大分削りましたが
200回コマンドを繰り返してこの時間なので
しかもmes命令結構使ってるし
比較命令は高速っぽいっすね。文字列でも。

という訳でswitchはifより二倍速いと
工夫してifの数を半分にすると
速さはあんまり変わらないという仮説です

あと、誤字すいませんでした
書式→書籍
me→mes
解決もつけときます



zakki

リンク

2021/8/16(Mon) 20:25:06|NO.93599

前提条件変えてしまってよければ、whitespaceだと動的にソースコードの自己書き換えが有ったりはしないので先に文字列を整数IDに変換しておいて、
ホットスポットでは整数比較にすると4倍速くらいになりました。
ラベル配列にすると5倍速くらいですが処理増やす時のメンテナンス性は落ちるかも。

mesが遅くて差が見えにくかったのでmesはコメントアウトしてループ回数増やして比較してます。


#runtime "hsp3cl" #uselib "Kernel32.dll" #cfunc GetTickCount "GetTickCount" #define UNKNOWN 0 #define VALUE 1 #define DISCARD 2 #define ADD 3 #define SUB 4 *START Ts=GetTickCount() memory = 0 str4input = "" int4input = 0 // TEST用文字列 // 入力ミスすることも考慮し無効な文字列も混ぜてます sdim commands,30,30 commands.0 = "123","456","789","1_23","add","!add","a-d-d","!A-D-D","discard","!discard","-987","-654","-123","-1_23","SUB","!SUB","S*U*B","!S-U-B","disc","!disc","" // 最初にコマンド列をパース dim commands_token,30 ldim commands_exec,30 repeat length(commands) str4input = commands.cnt mes str4input //////////////////////////////////////// _1st_ch = peek(str4input,0) if _1st_ch == '0' || _1st_ch >= '1'{ if _1st_ch <= '9' { commands_token.cnt = VALUE commands_exec.cnt = *exec_VALUE continue } } _2nd_ch = peek(str4input,1) if _1st_ch == '-'{ if _2nd_ch == '0' || _2nd_ch >= '1'{ if _2nd_ch <= '9' { commands_token.cnt = VALUE commands_exec.cnt = *exec_VALUE continue } } } switch commands.cnt case "stack_discard": case "!stack_discard": case "STACK_DISCARD": case "!STACK_DISCARD": case "discard": case "!discard": case "DISCARD": case "!DISCARD": case "Discard": case "!Discard": commands_token.cnt = DISCARD commands_exec.cnt = *exec_DISCARD swbreak //////////////////////////////////////// case "!+": case "+":case "add": case "!add": case "ADD": case "!ADD": case "Add": case "!Add": commands_token.cnt = ADD commands_exec.cnt = *exec_ADD swbreak case "!-": case "-": case "sub": case "!sub": case "SUB": case "!SUB": case "Sub": case "!Sub": commands_token.cnt = SUB commands_exec.cnt = *exec_SUB swbreak default commands_token.cnt = UNKNOWN commands_exec.cnt = *exec_UNKNOWN swbreak swend loop do_count = 0 commands_count = 0 commands_max =20 *begin do_count++ commands_count = do_count \ 20 if do_count >2000000{ T=GetTickCount()-Ts print T stop } //logmes "" + do_count + ":" + commands_count str4input = commands.commands_count token = commands_token.commands_count #if 1 //////////////////////////////////////// if token == VALUE { goto *begin } //////////////////////////////////////// switch token case DISCARD: // mes "!DISCARD\n" goto *begin swbreak case ADD: // mes "!ADD(!+)\n" goto *begin swbreak case SUB: // mes "!SUB(!-)\n" goto *begin swbreak swend // mes "Pardon?\n" goto *begin #else goto commands_exec.commands_count #endif *exec_VALUE goto *begin *exec_DISCARD // mes "!DISCARD\n" goto *begin *exec_ADD // mes "!ADD(!+)\n" goto *begin *exec_SUB // mes "!SUB(!-)\n" goto *begin *exec_UNKNOWN // mes "Pardon?\n" goto *begin



Y_repeat

リンク

2021/8/17(Tue) 00:17:27|NO.93601

こんばんわ。返信ありがとうございました。→zakkiさん

計測のため何百回かループさせてますが
今回は一つ命令を入力して実行して出力ってかんじなので
数値化はしずらいですね
whitespace言語を移植しようとしてたんですが上手くいかなくて
書籍の最初の方のプログラムみたい構成にしたら
上手くいったかんじです

CやC++のswitchは数値だしなーとは思いましたが
hspのswitchも数値にすれば相当速くなるっぽいすね
文字列も扱ってくれて嬉しくはありますが

入力を複数行にして文字列を数値ID化するのは今後の改善点ですね
複数行を毎回文字列比較してたら
それは効率悪いですね
現在の一回入力して一回実行する形式では
複数回の比較でも問題はなさそうという結論ではありました

ちなみに今回のTESTコードはズルをしていて
字句解析せずにtokenを分割した後の状態で配列変数に入れてます
その辺、RubyやPythonのwhitespace言語では言語の機能を利用して
字句解析しています。RubyやPythonに詳しくないのでどうやってるのか
よくわからなくて、トークンの切り出し方がわからず
whitespace言語をHSPに移植出来ないかんじです
whitespace言語の命令は移植してあったので
それを転用しているところが
whotespace言語をベースにしているという由来です
なんか書籍をベースにするのも問題ありそうで
なので書籍ではトークンのアルファベットの大文字小文字の違いは無視してますが
あえて無視しないかんじにしています。効率は悪くはあるんですが

mesは遅いかんじはしました
mesせずに文字列に数値なら1。ADDなら2。Pardonなら3とか
1byte加算して計測が終わってから出力しようかな。とは思いました
結論は出たのでしなくていいかな。とは思ってます

という訳で一行づつ記述していく計算機を作成していましたが
複数行の計算への移行において
各行の受理のかんじをまとめて表示していくかんじもいいかもですね

1 123
2 456
3 ADD
4 Pardon?
みたいにw 別にPardon?で問題なければそのまま動かす的な
作成していて、数独を解くようなかんじのプログラム言語があっても
いいんでない?とは思いましたが
プログラム全体を数独を解くようなかんじで作成していくかんじで
なんか僕のミニゲーム作成のかんじはそんなかんじします
「数独」の全体的に回答を絞っていって徐々に正解に近づいていくかんじを
指しています

プログラム作成も大分終わってて
リファクタリングの方針も決まり
後はマニュアル書きってとこです
めんどくさいですし、苦手ですが
残り約二か月。いいかんじで投稿出来そうなかんじです
(投稿作品がいいかんじなのかは不明ですw)
それではかさねがさねありがとうございました



Y_repeat

リンク

2021/9/2(Thu) 22:45:56|NO.93747

こんにちわ。switchを用いるリファクタリング大体終わりました
時期的にプロコンの締め切りまでまだちょっとあるので
簡単な処理の複数行読み込みに対応しようかな。と思ってます
計画にはなかったんですが
ここのスレのサンプルを書いた経験で
簡単な処理ならそんなに難しくないかな。と思いました

マニュアルは作成途中です
RPGツクールのマニュアルみたいな
(何年か前ちょくちょく見たかんじします)
項目を選べるマニュアル作成ツールないかなー?
と思いましたがみつからず
昔、見た気がしますが作成がめんどくさそうだった記憶もあり
HSPでザックリマニュアル作成しようかな。と思ってるところです

基本、一行づつ入力するスタイルですが
複数行読み込みにも対応するなら
コマンドはIDで保持した方が良さそうですね
zakkiさんありがとうございました
自分はサンプルスクリプトとか
目を通しただけではあんあまり理解出来ないタイプで
2回程、写経致しました
そんなに長くもないですし
もうちょっと写経しようかな。と思っております

自分、あんまりハートも強くないですし
自作のプログラムの話題とか
強心臓な人しか書けないもんなんかなーとも思いますが
ブログでやれとか思っている人もいるでしょうし
ここの掲示板の交流目的な利用への見解はどんなかんじなのかな?
とは思いました
ブログやwikiで書くのもいいですが
反響をもらえませんのでね



記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.93566への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

解決したら質問者本人がここをチェックしてください。

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

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