見てる感じ、単純にデータ数が多すぎてHSPというスクリプト言語の処理速度が見えてしまっている感じですね。
これだけ単純な処理だとアルゴリズム的な改良は無理なため、スクリプトの謂わば隙を突いた書き方が必要になってきます。
つまり、実行しているHSPの気持ちになる、ということですね…^^;;
手元で計測結果を元に、色々やってみました。
結局、大した成果にはならなかったですが、参考程度に。
○ 元のスクリプトと同じ
#include "winmm.as"
#define NOTES 1000
#define LENG 10000
ddim TMP_data,100000
timeGetTime : s = stat
repeat NOTES
repeat LENG,rnd(10000)
TMP_data(cnt)+=1.0*rnd(100)
TMP_data(cnt)=limitf(TMP_data(cnt),-32767.0,32767.0)
loop
loop
timeGetTime : e = stat
color :mes strf("OK : %d milliseconds", e-s)
スクリプト短くしたかったので#deffunc削ってみました、3150msくらい。
ちなみに#deffuncを削ったところで処理は変わらずでした。
NOTESの数が1000のオーダーなので、10000のLENGのオーダーに比べてほぼ差がなかったっぽいです。
◆型変換をなくす
スペースさんも仰っている方法ですが、自動でされる型変換は敢えて書かない方が早いです。
HSPは左の項に演算結果の型が合う(A+Bの結果はA)のと、A+=Bなどの自己代入は擬似的にはA=A+Bと同じなのを考えると、
これは
TMP_data(cnt)+=1.0*rnd(100)
これと同じ。
TMP_data(cnt)+=rnd(100)
これだけかよ、と思うかもしれませんがこれで2900msぐらい、なんと5%ぐらい削れる。
◆添字計算、代入を減らす
あんまり意識してないかもしれませんが、”A(cnt)”という記述は”Aという変数のcnt番目を取り出す”という処理なので、これだけで実は計算が走ります。
下らないかもしれませんが、これが
TMP_data(cnt)+=rnd(100)
TMP_data(cnt)=limitf(TMP_data(cnt),-32767.0,32767.0)
こうした方が早い、という理屈分かりますか?
t=TMP_data(cnt)+rnd(100)
TMP_data(cnt)=limitf(t,-32767.0,32767.0)
これで2750msくらい、更に同じく5%いかないぐらい削れる。
そして、この一時変数 t への代入、全くもって無駄でlimitfの中にしまえるの分かりますよね。
TMP_data(cnt)=limitf(TMP_data(cnt)+rnd(100),-32767.0,32767.0)
これで2350msくらい、更に10%ぐらい削れて、思ったより変数への代入が時間食っていることがわかったりします。
◆更に代入を添字計算をなくす
上述までで気付いたかもしれませんが、TMP_data(cnt)への読み込みと代入が減るとそれなりに効いてきたりします。
ところで、”NOTES個の、LENGの長さの波を足す”という処理ですが、加算は順序を好きに並べ替えていいので、このループの入れ子関係を逆にすると早くできるの、分かりますか?
例えば、提示して頂いた例だと(ランダム)オフセットが入ってたりランダム値加算なので実は無理なんですが、もし下記のような感じに書き下せるならば
repeat NOTES
repeat LENG
TMP_data(cnt)=limitf(TMP_data(cnt)+rnd(100),-32767.0,32767.0)
loop
loop
こう書き直せて
repeat LENG
gcnt = cnt
repeat NOTES
TMP_data(gcnt)=limitf(TMP_data(gcnt)+rnd(100),-32767.0,32767.0)
loop
loop
配列アクセスが内部のループでは固定されているため、一時変数に逃がせて
repeat LENG
gcnt=cnt
t=TMP_data(gcnt)
repeat NOTES
t=limitf(t+rnd(100),-32767.0,32767.0)
loop
TMP_data(gcnt)=t
loop
これで2350ms → 1800msまで削れます、下らないと思うかもしれませんが、実行しているHSPの気持ちになると確かに速くなる道理はあったりします。
上の変形するとgcntという一時変数も消せたりしますが、cntの読み込みは確か通常の変数より若干遅かった記憶があるので(今は違うかも?)、上の形の方が速いかもしれません。
あと、演算精度が int で十分なら、double は演算の仕方がちょっと特殊なので int にすると早くなったりします。
repeat LENG
gcnt=cnt
t=int(TMP_data(gcnt))
repeat NOTES
t=limit(t+rnd(100),-32767,32767)
loop
TMP_data(gcnt)=double(t)
loop
以上、私自身はこういった最適化すると徒に読みにくくなるのでお勧めはしませんが…。
どうしてもHSPで速くしたい場合は基本的に”変数の読み込み・書き込み”に気を使うと良いと思います。