HSPでのビット操作
qqq 2013/5/6(Mon) 09:49:49|NO.53826
さて、最近非常に大きなデータを扱うことになったのですが、
それが真と偽の区別しか必要ないデータなんです。
0と1だけの区別しかないのに1byteづつ使っているととんでもないことになる量なので、
ビット操作をしようということになりました。
で、文字列型変数を使うことにして、次のようなソースを書きました。
(下ソース自体はintでもdoubleでもいけると思います)
#module
#deffunc BitPokeO var _dat, int _n, int _f
//p1変数のp2 bit目を変更します。
//p2は0から開始します。
//p3には0かそれ以外を指定して、off/onとします。
_Chk =_n>>3
_Chkn =_n-(_Chk<<3)
if _f{
poke _dat,_Chk,peek(_dat,_CHk) or 1<<_Chkn
}else{
poke _dat,_Chk,peek(_dat,_CHk) and 1<<_Chkn xor peek(_dat,_Chk)
}
return
//"BitPokeO _a,0,1"を実行すると_aは1に、"BitPokeO _a,8,1"では256になります。
#global
#module
#defcfunc BitPeekO var _dat, int _n
//p1変数のp2 bit目を参照します。
//p2は0から開始します。
//返り値は0かそれ以外です。1以外が返る場合に注意してください。
_Chk =_n>>3
_Chkn =_n-(_Chk<<3)
return peek(_dat,_Chk) and 1<<_Chkn
#global
割り算とかも最初は考えたのですが、そもそもの用途からして、
この命令と関数は何度も実行されるものですよね。
実行時間が長くなると困るので、ビットシフトで代用しました。
それで、ここからが本題なのですが、
このソース、もっと早くはならないでしょうか。
何かいいお考えをお持ちの方は教えてください。
KA 2013/5/6(Mon) 10:33:07|NO.53828
>>1byteづつ使っているととんでもないことになる量なので、
>>ビット操作をしようということになりました。
なぜ8倍の処理を選ぶのか、その発想が分からない。
質問も具体性に欠け、スクリプトから読み解く気力も出てこない。
y.tack 2013/5/6(Mon) 11:40:34|NO.53830
僕が書くとこうなりました
#module
#defcfunc is_bit int n,int m
switch n
case 1:if m&1:return 1:return 0
case 2:if m&2:return 1:return 0
case 3:if m&4:return 1:return 0
case 4:if m&8:return 1:return 0
case 5:if m&$10:return 1:return 0
case 6:if m&$20:return 1:return 0
case 7:if m&$40:return 1:return 0
case 8:if m&$80:return 1:return 0
default:return 0
swend
dialog "error",1
return-1
#defcfunc is_bytes int bytes,int bytes_index,int n
switch bytes_index
case 1:return is_bit(n,bytes&$ff)
case 2:return is_bit(n,(bytes>>8)&$ff)
case 3:return is_bit(n,(bytes>>16)&$ff)
case 4:return is_bit(n,(bytes>>24)&$ff)
swend
dialog "error",1
return-1
#global
mes is_bit(2,3)
mes is_bit(3,3)
mes is_bytes($200,2,2)
mes is_bytes($300,2,3)
文字列管理はめんどくさいからintで済ますくらいです
Cだとswitch使った方が早そうですが
HSPのswitchはelseifみたいな印象があってどっちが早いかわからないです
0と1で1byteづつ使ってもとんでもない量にはならないような
じゃあ画像はどうなるんだ?という話で
0と1で1byteづつ使ってとんでもない量になるスクリプトは
SQLele使うといいかも
(いや。僕はまだ使ったことないんですが)
0と1の計算をとんでもない量計算するのは
PC(いやワークステーション向き計算?という意味で)の
範疇超えてる気がするんですがどうなのでしょうか?
僕もそんなにスキルありませんが可読範囲で十分早いような
いっそマシン語に移植するしかないという見解もありそうです
y.tack 2013/5/6(Mon) 11:59:33|NO.53831
>さて、最近非常に大きなデータを扱うことになったのですが、
>それが真と偽の区別しか必要ないデータなんです。
うーん。絶対Cで書いた方が早いような
GUIじゃなくて良さそうなのでHSP向きじゃない処理だと思います
インラインアセンブラも使えますし
ってCのインラインアセンブラは日本語の資料少ないんですが
Visual C++ Expressのインラインアセンブラに挑戦しても
マシン語学ぶより楽でしょう
なんかアプリ作成じゃなく一回きりの操作ぽいので
考えずにそのモジュールでガリガリ計算してれば
既に大分進んでるような
ツノン 2013/5/6(Mon) 16:58:57|NO.53844
以前書いたスクリプトから。
指定数のbit を完全に含む ビット列を作成して、各ビットの操作を行います。
//////////////////////////////////////////////////////////
//
// Name : BITSTRING_MCRS 1.00
// type : Header
// date : 2012/04/15(確認)
//
//////////////////////////////////////////////////////////
// ビット列を作成します。
// 主にアプリケーションで 1タイプのみBIT列を使用する場合に適しています。
// 引数として
// BITSTRG_ONE_ELEMENT_SIZE に 32 で割り切れる数字
// 1 2 4 8 16
// のいずれかを指定すると
// 1 要素の bit 数を指定できます。
// それ以外は1配列要素毎に無駄な領域が発生する恐れがあります。
#ifndef BITSTRG_ONE_ELEMENT_SIZE
#const global BITSTRG_ONE_ELEMENT_SIZE 1
#endif
#define global ctype MAKE32BITMASK(%1)\
((%1>=32)<<31|(%1>=31)<<30|(%1>=30)<<29|(%1>=29)<<28|(%1>=28)<<27|(%1>=27)<<26|(%1>=26)<<25|(%1>=25)<<24|(%1>=24)<<23|(%1>=23)<<22|(%1>=22)<<21|(%1>=21)<<20|(%1>=20)<<19|(%1>=19)<<18|(%1>=18)<<17|(%1>=17)<<16|(%1>=16)<<15|(%1>=15)<<14|(%1>=14)<<13|(%1>=13)<<12|(%1>=12)<<11|(%1>=11)<<10|(%1>=10)<<9|(%1>=9)<<8|(%1>=8)<<7|(%1>=7)<<6|(%1>=6)<<5|(%1>=5)<<4|(%1>=4)<<3|(%1>=3)<<2|(%1>=2)<<1|(%1>=1)<<0)
#const global BITSTRG_SHIFT_OFSET 32/BITSTRG_ONE_ELEMENT_SIZE
#const global BITSTRG_MASK MAKE32BITMASK(BITSTRG_ONE_ELEMENT_SIZE)
// インデックス を計算する
/*配列インデックス*/
#define global ctype bitstrg_Ai(%1) (%1/BITSTRG_SHIFT_OFSET)
/*ビットインデックス*/
#if (BITSTRG_ONE_ELEMENT_SIZE==1)
#define global ctype bitstrg_Bi(%1) ((%1\BITSTRG_SHIFT_OFSET))
#else
#define global ctype bitstrg_Bi(%1) ((%1\BITSTRG_SHIFT_OFSET)*BITSTRG_ONE_ELEMENT_SIZE)
#endif
// 配列の要素数を計算する。
#define global ctype bitstrg_CalcEleTotal(%1) \
(bitstrg_Ai(%1))+(bitstrg_Bi(%1)!=0)
// ビット操作
/*ビット列の作成*/
#define global CreateBitString(%1,%2)\
dim %1 , bitstrg_CalcEleTotal(%2)
/*指定ビットの切替*/
#define global ctype bitstrg_Xor(%1,%2=0,%3=BITSTRG_MASK)\
%1(bitstrg_Ai(%2)) ^ %3<<(bitstrg_Bi(%2))
/*指定ビットを立てる*/
#define global ctype bitstrg_Or(%1,%2=0,%3=BITSTRG_MASK)\
%1(bitstrg_Ai(%2)) | %3<<(bitstrg_Bi(%2))
/*指定ビットを読み込む*/
#define global ctype bitstrg_And(%1,%2=0)\
((%1(bitstrg_Ai(%2)) >> bitstrg_Bi(%2))&BITSTRG_MASK)
//######################### ここまで ##############################
// テスト
CreateBitString buf,80 // 80bit のビット列を作成
bitstrg_Or(buf,3) // 3 を立てる
bitstrg_Or(buf,5) // 5 を立てる
bitstrg_Or(buf,64) // 64を立てる
bitstrg_Or(buf,31) // 31を立てる
bitstrg_Or(buf,64) // 64を立てる
bitstrg_XOr(buf,31) // 31を切り替える
val = bitstrg_Or(buf,10) // 左辺の変数に対して代入すると、配列の変更後の値を読み出す。ビット列の変更はされない。
/*出力してみる*/
tx=""
repeat 80
tx+= ""+bitstrg_And(buf,cnt)
if(cnt\32==31):tx+=" "
loop
mesbox tx,ginfo_winx,ginfo_winy