数学関数

高校で習った三角関数というものをのを覚えていますか?

そうです、サイン・コサイン・タンジェントといったものです。

ココでは命令の紹介なので、三角関数自体がわからない方にとってはわかりにくいかもしれません。

わかりにくい方はHSP3側の紹介になりますが、HSP3側の入門ページを参考にするか

サーチエンジンで検索したり書籍等で調べるなりしてみてください。

半径「r」の円(要らない部分の省略のために半円)があります。

中点座標(0,0)から角度「θ(シータ)」方向へ「r」移動した点を(x,y)とします。

どういう時にコレを使うかというと、中点(開始点)から半径(長さ)進んだ位置の座標を求める時に重宝します。

具体的にはキャラがXやY方向だけでなく斜め(45度以外)にも進ませたい時や、

アナログの時計表示を作成する時に利用しなければならなくなると思います。

初めに書いたサインは上の図でr分のy、コサインはr分のx、タンジェントがx分のyとなる(はず)。

タンジェントは置いておいてサイン・コサインをもう少しわかりやすく(?)書くと、

サインは終了Y座標が開始Y座標からどれだけ離れているかを知ることが出来、

コサインが終了X座標が開始X座標からどれだけ離れているかを知ることが出来ます。

HSPext.DLLではemsinでサインとemcosでコサインを求めることが出来ます。

#include "hspext.as"
	cx=winx/2
	cy=winy/2
	color : boxf : color 255
	repeat 256
		emcos x,cnt
		emsin y,cnt
		line cx,cy,x+cx,y+cy
	loop
	stop

上記のサンプルを実行するとウィンドウの中心座標を中点として256個の点を円周上に均等に配置されます。

HSPext.DLLには2点間の角度を求めるタンジェントを求める命令はありませんが、

代わりに、X,Yの開始・終了位置がわかれば角度が求まるアークタンジェントと言うのはあり、

ematan命令を使うことで2点間の角度を求めることが出来ます。

#include "hspext.as"
	x=100
	y=100
	direction=0 ; 方角
	calculation=1 ; 角度計算スイッチ
	fs=20
	font "",fs
	repeat
		redraw 0
		color 255,255,255 : boxf : color 255
		pos x,y : mes "●"
		if calculation {
			emcos calcx,direction
			emsin calcy,direction
			ematan calc,calcx,calcy ; 進行方向を示す
			emcos calcx,calc ; 進行X方向の増減値
			emsin calcy,calc ; 進行Y方向の増減値
			calculation=0
		}
		line x+10,y+10,calcx >> 2+x+10,calcy >> 2+y+10
		redraw
		stick k,15
		if k & 1 : calculation = 1 : direction -= 2 : if direction < 0 : direction = 255
		if k & 4 : calculation = 1 : direction += 2 : if direction > 255 : direction = 0
		if k & 2 : x += calcx >> 5 : y += calcy >> 5 : if (x < 0) | (y < 0) | (winx-fs < x) | (winy-fs < y) : x-=calcx >> 5 : y -= calcy >> 5
		if k & 8 : x -= calcx >> 5 : y -= calcy >> 5 : if (x < 0) | (y < 0) | (winx-fs < x) | (winy-fs < y) : x+=calcx >> 5 : y += calcy >> 5
		wait 1
	loop

角度と言っても返ってくる値は0〜360あるわけではなくemsinemcosで使う0〜1.0までの固定少数です。

次の解説が長引きそうですし、この命令の使用頻度は低そうですのでコレくらいにしておきます(^^;

先ほどのemsinemcosに話を戻しまして、初めのサンプルを見てどう思いました?

線が約1.5度間隔で引かれていますので円と呼ぶには結構荒いですよね...?

これをもっと細かくすることは出来ないでしょうか。

まず荒いと思われる理由は何でしょう。それは小数点以下の桁数が少ない(精度が低い)んですね。

それではもっと細かく(精度を上昇)するにはどうすればよいのでしょう。

HSPext.DLLにはemathと言うものが存在します。

初期設定(emathを使用していない場合)は「整数24bit+少数8bit」となっています。

emathのパラメータで指定するのは、この少数部分で何ビットにするかです。

例えば12を指定すれば少数のビット精度が4bit高くなり、誤差が小さくなり正確な演算が出来ます。

ただし扱えるビット数は同じなので小数点以下の精度は上がりますが、整数の扱える範囲が減ってしまいます。

合計32bitですのでemathで12を指定すると「整数20bit+少数12bit」となるわけです。

emathでは2〜30の間の精度設定しか出来ません(十分ですが...)。

それでは早速精度を上げてみましょう。

#include "hspext.as"
	cx=winx/2
	cy=winy/2
	color : boxf : color 255,255
	accuracy=9 ; 小数点精度を1bit上げる
	emath accuracy
	redraw 0 ; コレを入れないと大分遅くなってしまいます
	repeat 256
		emcos x,cnt
		emsin y,cnt
		line cx,cy,x+cx,y+cy
	loop
	redraw
	stop

先ほどより精度が上がり少し間隔が細かくなりましたね。

…と、気づいたことありますよね?見ただけでパッとわかるかと思いますが(^^;

そう、引かれた線が下半分だけになっちゃいましたね。

それと細かく見ておられる方はもう一点気づかれたかと思います。

線の長さが伸びてすべてウィンドウ外まで出てしまっていますね。

それではそれぞれの理由と回避策を説明していきたいと思います。

なぜ下半分だけになったのか...?

それ以前になぜ上や横ではなく下なのか、から説明して行きましょうか。

下になった理由は、スタート地点(cnt=0でサイン=0,コサイン=-1)からスタートするからである。

1,2,3…と増えていくと開始から90度までサイン・コサインが上昇していきますよね?

まぁHSPではY方向が反対で下に行くほど大きくなるので間違いやすいですけど…。

この章の始めのほうでサインはY方向、コサインはX方向と書いたのでわかっていただけているかと思いますが、

それもわからない方は三角関数について、より詳しく解説されているページへ行くことをお勧めします。

順序がコレですのでアナログ時計の9時の方向から反時計回りに行くこともわかっていただけましたね?

コレの回避法はおいておいて、次になぜ半分だけなのかを・・・。

答えから書くと「整数のビット精度が1下がったから」です。

数値を1ビット右へシフトすると2分の1になると言うのはわかりますか?

2進数で表わしますので1ビット右シフトで2、2ビットで4、3ビットで8分の1になるわけです。

ですので公式(?)にすると、Nビット右シフトで2のN乗分の1となるわけですね。

コレがわからない方はビットシフトや2進数を説明しているページをご覧になることをお勧めします。

さてなぜ線が伸びたのでしょう?

答えとしてはxやyの値(256)が(512に)変わったからですね。

なぜコレも2倍になるのでしょう?

xやyはサイン・コサインで0〜1.0の値が入りますが、実際には少数値が入っていません。

うそだ、と思う方はemsinなどで入った数値を表示してみてください。

この整数値からHSPext.DLLが内部でビットシフトして少数値として扱うわけです。

HSP製作者ではありませんのでこれ以上の詳しいことはおにたまさんにでも尋ねてください(^^;

…でこれらの回避策ですが、変更されてしまっているところを逆にビットシフトしてしまえばいいわけです。

#include "hspext.as"
	cx=winx/2
	cy=winy/2
	color : boxf: color 255,255
	accuracy=12
	if accuracy>8 : adjustment=accuracy-8 ; 何ビットシフトすれば戻るか
	emath accuracy
	redraw 0
	repeat 256 << adjustment
		emcos x,cnt
		emsin y,cnt
		line cx,cy,x >> adjustment+cx,y >> adjustment+cy
	loop
	redraw
	stop

初めのものと同じ大きさで精度が高く(間隔が狭く)なったのを確認できますか?

この大きさで完全に隙間をなくそうとするには精度を18くらいまで上げる必要があると思います。

先ほど「実際には0〜1.0が入らない」と書きましたが厳密には入るけれど表示ができないということです。

HSPだけでは整数値しか扱えませんので、32ビット整数値となって表示されてしまうわけです。

コレでは現在どんな値なのかを自分の目でチェックすることが出来ませんね。

HSPext.DLLではこのemsinなどで使っている値を表示するために

数値を文字列に変換するemstrというものがあります。コレを使えば確認が出来ますね?

#include "hspext.as"
	font "MS ゴシック",10
	pos 0,0 : mes "角度"
	pos 30,0 : mes "sin値"
	msg=""
	repeat 256
		tmp=cnt+1
		emsin sin,cnt
		emstr msg,sin
		color 255
		pos cnt/46*110+5,cnt\46*10+15 : mes tmp
		color
		pos cnt/46*110+25,cnt\46*10+15 : mes msg
	loop
	redraw
	stop

他にもemstr命令の逆の役割、文字列から小数にするemcnv命令、

それに少し似たemintという小数から整数にするものもあります。

これらの詳細な説明は一飛ばして、この章最後に平方根を求めるemsqrを書いておきます。

平方根とかルートとか言う言葉は聴いたことありますよね?

2乗するとNになる数をNの平方根と呼んでいます。

例えば2乗して4になる数というのは2ですね?こういった割り切れる数はいいのですが、

2乗して3になる数は?5になる数は?6は?ほとんどの数値が割り切れず求めることが出来ませんよね?

まぁチラッと書いておくと割り切れる数は「1,4,9,16,25,36,49,64,81…」とこういったものです。

それでルートですが、書かれている平方根を読む時に「平方根」ではなく「ルート」と読むのです。

平方根のマークは「√」というのはご存知ですよね?

またまた余談ですが、2乗してNになる数は1つだけではありません。+√Nと-√N二つになります。

HSPで扱うには直接は関係ないかと思いますが覚えておいてくださいね。

Tipsに標準命令だけで平方根を求めるやり方を載せています。

興味がある方はコチラから一度見てみてください。

この章ものすごく長引いてしまいましたが参考になれば幸いです。