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


HSPTV!掲示板


未解決 解決 停止 削除要請

2018
0418
SealHSPの命令でHSPの命令を作るスレ2解決


Seal

リンク

2018/4/18(Wed) 17:03:47|NO.84054

HSP命令でどの位HSP命令を作れるかというスレを立てました。


#module #uselib "gdi32.dll" #func TextOutA "TextOutA" int, int, int, str, int #func SetTextColor "SetTextColor" int, int #undef color #deffunc color int prm1, int prm2, int prm3 cr = prm1 cg = prm2 cb = prm3 SetTextColor hdc, ( cr | cg << 8 | cb << 16) return 0 #undef pos #deffunc pos int prm1, int prm2 posx = prm1 posy = prm2 return 0 #undef mes #deffunc mes str prm1 mref BMSCR, 67 redraw 0 txt = prm1 TextOutA hdc, posx, posy, txt, strlen(txt) posy = posy + abs(BMSCR.49) + 2 redraw 1 return #undef print #deffunc print str prm1 txt = prm1 mes txt return 0 #undef abs #defcfunc abs int prm1 n = prm1 if n = 0 { return 0 } if n < 0 { return n * -1 } if n > 0 { return n } return 0 #global color 0, 0, 0 pos 20, 20 mes "HSPの命令でHSPの命令を作るスレ" print "HSPの命令でHSPの命令を作るスレ"

上の例のスクリプトは color pos mes print を HSP や WIN32API を使ったサンプルです。

■ルール
・例えば、sin関数を定義する時にそのまま return sin(n) を戻り値にするのは無しです。
 理由としては 簡単すぎ? ですかねぇ...
・API関数は使っていいです

よろしくお願いします^^



この記事に返信する


いののて

リンク

2018/4/18(Wed) 19:47:37|NO.84058

面白そうだったので、ginfo関数をHSPで再現してみました。
Windowsに関する取得はWINAPIを、HSPに関する取得はBMSCR構造体とHSPCTX構造体を使用しました。

加速度センサーとジャイロセンサーの値の取得方法が良く分からなかったので、それは実装していません。
#module mod_ginfo
#undef ginfo #uselib "user32.dll" #func GetCursorPos "GetCursorPos" int #cfunc GetForegroundWindow "GetForegroundWindow" #func GetClassName "GetClassNameA" int, int, int #func GetWindowLong "GetWindowLongA" int, int #func GetWindowRect "GetWindowRect" int, int #func GetClientRect "GetClientRect" int, int #cfunc GetDC "GetDC" int #func ReleaseDC "ReleaseDC" int, int #cfunc GetSystemMetrics "GetSystemMetrics" int #uselib "gdi32.dll" #cfunc GetDeviceCaps "GetDeviceCaps" int, int #define GWL_USERDATA (-21) #define RASTERCAPS 38 #define RC_PALETTE 0x0100 #define SM_CXSCREEN 0 #defcfunc ginfo int id switch id case 0 //スクリーン上のマウスカーソルX座標 case 1 //スクリーン上のマウスカーソルY座標 dim pt, 2 GetCursorPos varptr(pt) return pt(id) swbreak case 2 //アクティブなウィンドウID dim hWindow sdim sClassName, 0x200 hWindow = GetForegroundWindow() //最前面ウィンドウを取得 GetClassName hWindow, varptr(sClassName), 0x200 if (sClassName == "hspwnd0"){ //HSPのウィンドウか判定 return GetWindowLong(hWindow, GWL_USERDATA) }else: return -1 swbreak case 3 //操作先ウィンドウID mref bmscr, 67 return bmscr(18) // bmscr.wid swbreak case 4 //ウィンドウの左上X座標 case 5 //ウィンドウの左上Y座標 case 6 //ウィンドウの右下X座標 case 7 //ウィンドウの右下Y座標 dim rc, 4 GetWindowRect hwnd, varptr(rc) return rc(id-4) swbreak case 8 //ウィンドウの描画基点X座標 case 9 //ウィンドウの描画基点Y座標 mref bmscr, 67 return bmscr(id-8+23) // bmscr.viewx / bmscr.viewy swbreak case 10 //ウィンドウ全体のXサイズ case 11 //ウィンドウ全体のYサイズ dim rc, 4 GetWindowRect hwnd, varptr(rc) return (rc(id-10+2)-rc(id-10)) swbreak case 12 //クライアント領域Xサイズ case 13 //クライアント領域Yサイズ dim rc, 4 GetClientRect hwnd, varptr(rc) return (rc(id-12+2)-rc(id-12)) swbreak case 14 //メッセージの出力Xサイズ case 15 //メッセージの出力Yサイズ mref bmscr, 67 return bmscr(id-14+68) // bmscr.printsize.cx / bmscr.printsize.cy swbreak case 16 //現在設定されているカラーコード(R) case 17 //現在設定されているカラーコード(G) case 18 //現在設定されているカラーコード(B) mref bmscr, 67 return peek(bmscr(40), (id-16)) //bmscr.color swbreak case 19 //デスクトップのカラーモード hDesktopDC=GetDC(0) mode = (GetDeviceCaps(hDesktopDC, RASTERCAPS) & RC_PALETTE)!=0 ReleaseDC 0, hDesktopDC return mode swbreak case 20 //ウィンドウ全体のXサイズ case 21 //ウィンドウ全体のYサイズ return GetSystemMetrics(id-20+SM_CXSCREEN) swbreak case 22 //カレントポジションのX座標 case 23 //カレントポジションのY座標 mref bmscr, 67 return bmscr(id-22+27) // bmscr.cx / bmscr.cy swbreak case 24 //メッセージ割り込み時のウィンドウID mref hspctx, 68 return hspctx(201) // hspctx.intwnd_id swbreak case 25 //未使用ウィンドウID nUnusedID = 0 //ループをまわして、BMSCR構造体が初期化されていなかったら未使用ウィンドウIDとする。 repeat 500 mref bmscr, 96+cnt if (varptr(bmscr) == 0){ //変数のポインタが無効だったら未使用 nUnusedID = cnt break } loop return nUnusedID swbreak case 26 //画面の初期化Xサイズ case 27 //画面の初期化Yサイズ mref bmscr, 67 return bmscr(id-26+1) // bmscr.sx / bmscr.sy swbreak swend return 0 #global screen 0, 640, 600 s(0)="スクリーン上のマウスカーソルX座標" s(1)="スクリーン上のマウスカーソルY座標" s(2)="アクティブなウィンドウID" s(3)="操作先ウィンドウID" s(4)="ウィンドウの左上X座標" s(5)="ウィンドウの左上Y座標" s(6)="ウィンドウの右下X座標" s(7)="ウィンドウの右下Y座標" s(8)="ウィンドウの描画基点X座標" s(9)="ウィンドウの描画基点Y座標" s(10)="ウィンドウ全体のXサイズ" s(11)="ウィンドウ全体のYサイズ" s(12)="クライアント領域Xサイズ" s(13)="クライアント領域Yサイズ" s(14)="メッセージの出力Xサイズ" s(15)="メッセージの出力Yサイズ" s(16)="現在設定されているカラーコード(R)" s(17)="現在設定されているカラーコード(G)" s(18)="現在設定されているカラーコード(B)" s(19)="デスクトップのカラーモード" s(20)="ウィンドウ全体のXサイズ" s(21)="ウィンドウ全体のYサイズ" s(22)="カレントポジションのX座標" s(23)="カレントポジションのY座標" s(24)="メッセージ割り込み時のウィンドウID" s(25)="未使用ウィンドウID" s(26)="画面の初期化Xサイズ" s(27)="画面の初期化Yサイズ" foreach s y = ginfo(23) pos 0, y: mes s(cnt) pos 320, y: mes ginfo(cnt) loop



あらや(旧名あまら)

リンク

2018/4/19(Thu) 21:15:27|NO.84061

少し前に別のスレッドでsinとcosをやったので
ついでに数学関係の関数をやってみました。

absをSealさんとは別の方法でやってますが特に他意はありません。
absfをモジュール内の色んな所で使っているので
そのおまけでabsもabsfと同じ方法で入れてみただけです。

M_PI(円周率)やdeg2rad、rad2deg(角度変換系)はそのまま使っていますが
これは定数とかマクロなんで、新たに定義してもコピペに近くなりそうなんで
そのまま使わせてもらいました。


ちなみに、当然ですが本家HSPと比較すると若干速度が遅いです。
精度も微妙……と言いたかったんですが、
試したところ場合によっては本家より正確な数値が出ることもありました。

まあほとんどは下1〜2桁(小数点以下15〜16桁程度)に誤差が出てしまうんですが
その辺は見逃してください。<(_ _)>

#module // abs #undef abs #defcfunc abs int p1 if( p1 < 0 ) { return -p1; } return p1; // absf #undef absf #defcfunc absf double p1 if( p1 < 0.0 ) { return -p1; } return p1; // limit #undef limit #defcfunc limit int p1, int p2, int p3 if(p1 < p2):return p2; if(p1 > p3):return p3; return p1; // limitf #undef limitf #defcfunc limitf double p1, double p2, double p3 if(p1 < p2):return p2; if(p1 > p3):return p3; return p1; // logf テイラー展開でlogfの計算 0や負数のときの戻り値はHSPに準拠 #undef logf #defcfunc logf double p1 if( p1 < 0.0 ) { prm01 = 0xFFF80000; drc = 0.0; lpoke drc, 4, prm01; } else:if( p1 == 0.0 ) { prm01 = 0xFFF00000; drc = 0.0; lpoke drc, 4, prm01; } else:if( p1 == 2.0 ) { drc = 0.693147180559945309; } else:if( p1 < 2.0 ) { drc = _logf(p1); } else { prm01 = 1.0; prm02 = 1.0; repeat -1 prm02 *= 2.0; prm03 = p1 / prm02; if( prm03 <= 2.0 ):break; prm01 += 1.0; loop drc = prm01 * 0.693147180559945309 + _logf(prm03); } return drc; // logfのサブルーチン #defcfunc _logf double p1 prm_01 = p1 - 1.0; prm_02 = prm_01; iprm_01 = 2; repeat -1 prm_02 *= p1 - 1.0; prm_03 = prm_02 / iprm_01; if( absf(prm_03) < 0.0000000000000001 ):break; if( (iprm_01\2) == 0 ) { prm_01 -= prm_03; } else { prm_01 += prm_03; } iprm_01++; loop return prm_01; // expf マクローリン展開でexpfの計算 オーバーフローやアンダーフローの精度は標準関数より若干低い #undef expf #defcfunc expf double p1 if( absf(p1) < 0.00000000000000000001 ):return 1.0; if( p1 < -745.0 ):return 0.0; // アンダーフロー1 if( p1 > 707.0) { // オーバーフロー prm01 = 0x7FF00000; drc = 0.0; lpoke drc, 4, prm01; return drc; } prm_d = 1.0; prm_e = 1.0; drc = 1.0; lflag = 0; prmlast = 0.0; // オーバーフローの備え prm00 = 0x7FF00000; // lpoke prmlast, 4, prm00; // repeat -1, 1 await 0 prm_d = drc; prm_e = prm_e * absf(p1) / double(cnt); if( prmlast == prm_e ) { if(p1 <= 0.0) { drc = 1.0 / drc; } lflag = 1; break; } drc += prm_e; if( (absf(drc-prm_d)/absf(prm_d)) < 0.00000000000000000001 ) { if(p1 <= 0.0) { drc = 1.0 / drc; } lflag = 1; break; } loop if( lflag == 1 ) { return drc; } else { return 0.0; // アンダーフロー2 } // powf expfとlogfを利用して計算 #undef powf #defcfunc powf double p1, double p2 if( p1 == 0.0 ) { // 底が0の場合 if( p2 == 0.0 ) { // 指数が0ならば1 return 1.0; } else:if( p2 < 0.0 ) { // 指数が負数ならばエラー pdrc = 0.0; prm01 = 0x7FF00000; lpoke pdrc, 4, prm01; return pdrc; } else { // その他の場合は0 return 0.0; } } if( p1 < 0.0 ) { // 底が負数の場合 if( p2 == 0.0 ) { // 指数が0ならば1 return 1.0; } else:if( (p2\1.0) == 0.0 ) { // 指数が整数ならばループで計算 pdrc = p1; repeat int(absf(p2))-1 pdrc *= p1; loop return pdrc; } else { // その他の場合はエラー pdrc = 0.0; prm01 = 0xFFF80000; lpoke pdrc, 4, prm01; return pdrc; } } if( (p2\1.0) == 0.0 ) { // 指数が整数ならばループで計算 pdrc = p1; repeat int(absf(p2))-1 pdrc *= p1; loop } else { pdrc = expf( p2 * logf(p1) ); } return pdrc; // sqrt 平方根の計算方法を利用 #undef sqrt #defcfunc sqrt double p1 if( p1 == 0.0 ):return 0.0; // 0の場合 if( p1 < 0.0 ) { // 負数の場合はエラー drc = 0.0; prm01 = 0xFFF80000; lpoke drc, 4, prm01; return drc; } prm01 = p1 / 2.0; prm02 = 0.0; drc = 1.0; repeat -1 prm02 = drc; drc = (drc + p1 / drc) / 2.0; if( drc == prm02 ):break; loop return drc; // sin テイラー展開でsinの計算 #undef sin #defcfunc sin double p1 prm01 = p1; prm02 = prm01; iprm01 = 1; drc = prm01; repeat -1 prm02 *= ( -prm01*prm01 / (2.0*iprm01*(2.0*iprm01+1.0)) ); drc += prm02; iprm01++; if( absf(prm02) <= 0.00000000000000000001 ):break; loop return drc; // cos テイラー展開でcosの計算 #undef cos #defcfunc cos double p1 prm01 = p1; prm02 = 1.0; iprm01 = 1; drc = 1.0; repeat -1 prm02 *= ( -prm01*prm01 / ((2.0*iprm01-1.0)*2.0*iprm01) ); drc += prm02; iprm01++; if( absf(prm02) <= 0.00000000000000000001 ):break; loop return drc; // tan 単純にsin/cosを返す #undef tan #defcfunc tan double p1 return sin(p1) / cos(p1); // atan テイラー展開でatanの計算 戻り値の範囲は -パイ〜パイ(度数にすると -180度より大きく180度以下) #undef atan #defcfunc atan double p1, double p2 H_PI = M_PI / 2.0; Q_PI = M_PI / 4.0; if( p2 == 0.0 ) { if( p1 > 0.0 ):return H_PI; // Xが0で Yが正数 if( p1 < 0.0 ):return -H_PI; // Xが0で Yが負数 if( p1 == 0.0 ):return 0.0; // 両方0 } atdrc = 0.0; root2 = sqrt(2.0); root2m1 = root2 - 1.0; root2p1 = root2 + 1.0; if( p2 < 0.0 ) { // X値が負数ならば第二象限か第三象限 if( p1 < 0.0 ) { // Y値も負数ならば第三象限 Quad = 3; } else { // Y値が正数ならば第二象限 Quad = 2; } } else { // X値が正数ならば第一象限か第四象限 if( p1 < 0.0 ) { // Y値が負数ならば第四象限 Quad = 4; } else { // Y値が正数ならば第一象限 Quad = 1; } } x = p1 / p2; if( x < 0.0 ) { x = -x; x2 = -p2 / p1; } else:if( p1 != 0 ) { x2 = p2 / p1; } if( x != 0.0 ) { // 精度を保ちつつ高速化するために4つの条件に分割する if( (0.0 < x) && (x <= root2m1) ) { // xが 0 〜 √2-1 の範囲の場合 atdrc = _atan( x ); } else:if( (root2m1 < x) && (x < 1.0) ) { // xが √2-1 〜 1 の範囲の場合 atdrc = Q_PI - _atan( (1.0-x) / (1.0+x) ); } else:if( (1.0 <= x) && (x < root2p1) ) { // xが 1 〜 √2+1 の範囲の場合 atdrc = Q_PI + _atan( (1.0-x2) / (1.0+x2) ); } else:if( x >= root2p1 ) { // xが √2+1 以上の場合 atdrc = H_PI - _atan( x2 ); } } else { atdrc = 0.0; } switch Quad case 2 atdrc = M_PI - atdrc; swbreak; case 3 atdrc = atdrc - M_PI; swbreak; case 4 atdrc = -atdrc; swbreak; default swbreak; swend return atdrc; // atanのサブルーチン #defcfunc _atan double p1 sdrc = 0.0; prm02 = 1.0; prm03 = 0.0; prm04 = -1.0; prm05 = p1; prm06 = p1*p1; prmlast = 0.0; // オーバーフローの備え prm00 = 0x7FF00000; // lpoke prmlast, 4, prm00; // repeat -1 prm04 = -prm04; prm03 = prm04 * prm05 / prm02; sdrc += prm03; if( absf(prm03) == prmlast ):break; // オーバーフロー if( absf(prm03) < 0.00000000000000000001 ):break; prm05 *= prm06; prm02 += 2.0; loop return sdrc; #global log = logf(5.0); mes strf("5の対数:\t\t\t\t\t%.16f", log); exp = expf(log); mes strf("5の対数の指数 精度が高いと5.0になる:\t\t%.16f", exp); pow = powf(2.0, 10.0); mes strf("2の10乗 整数乗のときはループで掛けてるだけ:\t%.16f", pow); root3 = sqrt(3.0); mes strf("\n3の平方根(sqrt(3.0)の場合):\t\t\t%.16f", root3); root3_2 = powf(3.0, 0.5); mes strf("3の平方根(powf(3.0, 0.5)の場合):\t\t%.16f", root3_2); sin60 = sin(deg2rad(60.0)); cos60 = cos(deg2rad(60.0)); tan60 = tan(deg2rad(60.0)); mes strf("\nsin60度 = √3 / 2:\t\t\t%.16f", sin60); mes strf("cos60度 = 1 / 2:\t\t\t%.16f", cos60); mes strf("tan60度 = √3 / 1:\t\t\t%.16f", tan60); arctan = atan(root3, 1.0); mes strf("\natan(√3 , 1):\t\t\t\t%.16f", arctan); datan = rad2deg(arctan); mes strf("atan(√3 , 1)を度数に変換:\t\t%.16f", datan);
グラフィック系もいくつかはAPIを多用すれば比較的簡単にできそうなんですが
redrawで更新しないと画面に反映されなそうなんで、ちょっと迷ってます。


atanに変なバグがあったのをコッソリ修正。



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