1 名前:デフォルトの名無しさん [2006/09/16(土) 09:46:26 ] 前スレ ビット演算 pc8.2ch.net/test/read.cgi/tech/1123918075/ 関連スレ アセンブラ… (゜□゜) ↑アッー!↓ pc8.2ch.net/test/read.cgi/tech/1148402614/ 関連情報 Hacker's Delight ttp://www.hackersdelight.org/ ハッカーのたのしみ―本物のプログラマはいかにして問題を解くか ttp://www.amazon.co.jp/exec/obidos/ASIN/4434046683 ビットを数える・探すアルゴリズム ttp://www.nminoru.jp/~nminoru/programming/bitcount.html Bitboard ttp://en.wikipedia.org/wiki/Bitboard
357 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 01:08:45 ] 56の余りってなにさ?
358 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 01:17:06 ] x % 56でも計算したいんじゃね?
359 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 07:26:57 ] x % 56だと 2のベキ乗じゃないからビット演算1発では出来ないな ttp://www.tensyo.com/urame/date/dayTips.shm ここの後ろの方にビットマスクと繰り返し演算で剰余を求める方法がある
360 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 07:35:52 ] 定数での除算って、こんなに繰り返し必要だったっけ? 3、4回の演算で書けたような気が・・・って、俺の記憶違いか?
361 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 07:37:37 ] それ、もしかしたら、2のべき乗での除算?
362 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 07:40:38 ] いや、それなら1回でいけるし。 あれ? 乗算だっけ?
363 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 07:42:31 ] ああ、何か乗算だった気もしてきた。スマン。
364 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 07:50:41 ] 2^N>=b となるNを求める(2^N == 1<<N) ・・・・・ N=6 2^N=64 B=2^N-b ・・・・・・ 64 -56 = 8 C=2^N-1 ・・・・・・ 64 - 1 = 63 while(a>=2*b){ B *(a>>N) + a&C }; while(a >=56*2 ){ 8 *(a>>6 ) + a&63 }; while(a >=56*2 ){ ( (a>>6 ) <<3 ) + a&63 }; 1ループで3ビット改善するから 32bitなら 最大10回ちょっとのループか
365 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 08:00:17 ] 56*73 =4088 で 2^12-8 だから a = ( (a>>12 )<<3 ) + a & 4095; を 前段でやれば改善するんじゃないかな
366 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 09:49:41 ] 最近のコンパイラは定数の割り算は掛け算に置き換えるね。 56で割るロジックをコンパイルしたら、-1840700269を掛けた後に ビットシフトと足し算をしていた。それ以上追っかけるのはパス。
367 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 09:51:15 ] インテルのコンパイラで a=a%56 の出力はこんな感じ(aはunsigned int)。 LARGE_INTEGER li; li.QuadPart = UInt32x32To64(a>>3 ,0x24924925); int d = li.HighPart; a -= ((d<<3)-d)<<3; aがsigned intの場合は、もう少し複雑。
368 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 10:11:46 ] なるほど、>366の数値が0x92492493だからシフト量が違う同じビットパターンなのか。
369 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 10:17:29 ] でもまあPCのCPUみたいに掛算が高速だったらって前提だな。 1チップとかだと 掛算はビットサイズに応じたサイクル数かかるし 掛け算持ってないCPUもあるし
370 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 10:21:39 ] 大丈夫、そういうCPUは割り算も遅い。
371 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 10:26:29 ] a = ( (a>>18 )<<3 ) + a & ((1<<18)-1); a = ( (a>>12 )<<3 ) + a & 4095; a = ( (a>>9 )<<3 ) + a & 511 a = ( (a>>6 ) <<3 ) + a & 63; a = ( (a>>6 ) <<3 ) + a & 63; while(a>=56) a-=56; これならどうだろ?
372 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 10:34:31 ] 演算子の数が20を超えてるな。 素直にdiv使った方が速いかもしれない。
373 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 10:45:50 ] もうちょっとバランスをうまく取れば、1行減らせるかもな
374 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:08:06 ] 結局 3bit 単位だからなあ 最初は a = ( (a>>15 )&(-7) ) + a & ((1<<18)-1); か a = ( (a>>12 )&(-7)) + a & ((1<<15)-1); のどっちかで、どっちも32->18.4bit 次は a = ( (a>>6 )&(-7) ) + a & 511 でも12.5bit a = ( (a>>9 )&(-7) ) + a & 4095; でも12.5bit あとは3ビットづつしか落とせない。 無理
375 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:17:53 ] あ、 a = ( (a>>18 )<<3 ) + a & ((1<<18)-1); a = ( (a>>12 )<<3 ) + a & 4095; a = ( (a>>6 ) <<3 ) + a & 63; a = ( (a>>6 ) <<3 ) + a & 63; while(a>=56) a-=56; とやれば、最後の while はせいぜい3回のループでいいか
376 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:26:49 ] >>372 div 命令は、持っていてもbit数のサイクルかかるのが殆どだよ。 だから >>366-367 のような最適化がされるんだし
377 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:33:21 ] ただ PC の場合はレイテンシがかかるだけだから、divを使った方が速いかもしれないな。
378 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:37:09 ] >>367 ここまでしても idiv より速いのか・・・。
379 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:48:18 ] Pentium II およびPentium III プロセッサの実行ユニット 整数乗算は レイテンシ4、スループット1/ サイクル 除算は浮動小数点ユニットで行われ FDIV 命令 レイテンシ: 単精度17 サイクル、倍精度36 サイクル、拡張精度56 サイクル だから、桁違いにレイテンシが大きい。
380 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:50:39 ] 浮動小数点ユニットで行われるのか?!
381 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 11:58:11 ] だって 整数乗算ユニットってのはブロック図にあるが、 整数除算ユニットってのはどこにも無いだろ? 除算ってのはコストのわりに利用頻度が少ないから、どうせ浮動小数点ユニットもってるからそっちで計算させてるのさ 仮に、整数演算ユニットで除算をしたとしても、結局32サイクルはかかるし、その間加減算比較ユニットの一つが潰れてしまうからな
382 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 12:14:11 ] そうだったのか・・・。 そら遅いわな。
383 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 12:27:02 ] >>381 これ以上はスレ違いになるがつっこませてくれ。 浮動小数点ユニットがIEEE754(だったっけ)で処理する場合、単精度で23ビット、倍精度で52ビットの精度だろ。 被序数が32ビット整数ならともかく、64ビット整数の除算は精度の問題上アウトだぞ。
384 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 12:34:23 ] >>383 Intel 系の浮動小数点ユニットは 拡張倍精度(80ビット/仮数部64ビット)で行われてるから大丈夫。
385 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 12:44:20 ] >>384 まじか!と思って何年も開いていない重たいバインダーを紐解いてみたら、たしかにそう書かれているな。 しかも本当は63ビット精度なのに、ケチりビットをケチらない荒技で対処してるし・・・。 そのうえx87コプロに限ればつねに拡張倍精度で計算されることになってたりして、もうね、馬(ry。
386 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 13:02:46 ] 56 = 7*2^3 だから x % 56 = (x % 7)<<3 + (x & 7) x/7 を round(2^32/7 )>>32 で近似したのが >>367
387 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 13:07:24 ] しかし、1/7って面白いなぁ。10進だけでなく16進でも綺麗な循環小数になるんだな。
388 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 13:08:10 ] もしかして >>375 のような事しても idiv 使うより速いって事はありえるのか?
389 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 16:51:54 ] >>388 実際に速度を比較してみれば? Cの場合、&より+の方が優先順位が高いので、 >>375 の&演算には括弧が必要だね。
390 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 17:06:59 ] そうだね。
391 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 18:03:24 ] やってみた。 function getRDTSC: int64; asm DW $310F //RDTSC end; var ww:Integer; procedure TForm1.Button1Click(Sender: TObject); const CNT=100000; var t1,t2,t3:int64; i,a:Integer; begin t1:=getRDTSC; for i := 1 to CNT do begin a := i; a := ((a shr 15) and 7) + (a and ((1 shl 18) - 1)); a := ((a shr 9) and 7) + (a and 4095); a := ((a shr 3) and 7) + (a and 63); a := ((a shr 3) and 7) + (a and 63); while a >= 56 do a := a - 56; ww:=a; {mod と同じになるように} end; t2:=getRDTSC; for i := 1 to CNT do ww:=i mod 56;{ローカル変数に代入すると最適化で消えるので} t3:=getRDTSC; Memo1.Lines.Add(format('T2-T1 %10d',[t2-t1])); Memo1.Lines.Add(format('T3-T2 %10d',[t3-t2])); end; --------------- T2-T1 1610740 T3-T2 4317497 間違いでなければ mod 命令より速い
392 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 18:06:18 ] そうだね。
393 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 18:09:15 ] 上の and 7 は and -8 の間違いだった
394 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 18:33:37 ] でも、掛算を使うのはさらに半分だった。 for i := 1 to CNT do begin a := i shr 3; asm mov eax,$24924925; IMUL a; mov a,EDX; end; ww := i - ((a * 7) shl 3); // if ww<> (i mod 56) then Memo1.Lines.Add( 'Err'); end; t4 := getRDTSC; T2-T1 169613675 T3-T2 436034967 T4-T3 86040347
395 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 18:40:43 ] 結局 idiv : ビット演算 : 掛算の 重さは およそ 5 : 2 : 1 だった。 ビット演算 思ったよりガンバレるな。
396 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 19:24:47 ] これを高級言語で書いたら他の人に白い目で見られるだけならまだいいんだけど ひどい場合は書き直しすら命じられまする(´・ω・`)
397 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 19:44:35 ] そうだね。
398 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 20:36:07 ] >>396 高級言語の目的の一つが可読性の向上だからね。 コメントで解説いれても却下される場合すらあると思うよ。
399 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 20:48:20 ] 除算命令がないCPUなら有効だろうけど x % 60 が欲しい時とか、いちいち変換が大変だよな
400 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 21:47:03 ] 導出は機械的なプロセスだから、スクリプトみたいなのでサクッと求めるといいと思う。 可能なら、最適化の一環としてコンパイラに組み込むのがベストだが。
401 名前:デフォルトの名無しさん mailto:sage [2007/06/22(金) 23:23:02 ] だから、掛け算化はgccでもやってるって。
402 名前:デフォルトの名無しさん mailto:sage [2007/06/23(土) 00:18:01 ] >>401 ほんとにやってる?やらない場合も多いけど 絶対さぼってる
403 名前:デフォルトの名無しさん mailto:sage [2007/06/23(土) 01:26:20 ] 昔のx86みたいにALUしかないCPUはそういう風にやってたのかぁ、勉強になりました。
404 名前:デフォルトの名無しさん mailto:sage [2007/06/23(土) 01:29:46 ] >>403 定数割り算の掛け算化が行われない例があれば、逆に教えて欲しい。 まさか、最適化オプションを指定しないとしてくれないなんて言わないよね。
405 名前:デフォルトの名無しさん mailto:sage [2007/06/23(土) 01:31:50 ] >>404 深く考えず単純に引き算かと 今考えると空恐ろしいやり方だw
406 名前:デフォルトの名無しさん mailto:sage [2007/06/25(月) 10:58:28 ] >404は>402宛てなんだろうなぁ。それはいいけど、>405は何を言いたいのだろう……
407 名前:デフォルトの名無しさん mailto:sage [2007/06/25(月) 19:13:34 ] きっと8086には除算命令が無いと思ってるんだろう。
408 名前:デフォルトの名無しさん mailto:sage [2007/06/25(月) 19:57:27 ] Pen3では除算を浮動小数点ユニットでされるというのを見て、 浮動小数点ユニットが無い時には除算も無かったと思ったのかな 除算そのものはシフト減算比較の繰り返しで出来るから サイクル数さえ必要なだけかければマイクロプログラム方式ならそうコストかからない 掛け算と変わらない。
409 名前:405 mailto:sage [2007/06/26(火) 07:50:34 ] >>406 あ、ほんとだね >>407 ,408 んにゃ、引き算の連続で商余求めてたのかなと
410 名前:デフォルトの名無しさん mailto:sage [2007/06/26(火) 08:23:37 ] これは固定での剰余だから高速化出来るのであって 変数での剰余になると、結局コードで書いても加え戻し法(復元法)とかになるので 除算命令使った方がやっぱり速い。
411 名前:デフォルトの名無しさん mailto:sage [2007/06/28(木) 00:42:51 ] DSP(やCell)では逆数をニュートン法で求めるのが定番
412 名前:デフォルトの名無しさん mailto:sage [2007/07/08(日) 16:40:57 ] 8086で除算命令使うとCPUの方で乗算とシフト命令に解釈しなおす訳? ということは除算命令自体はマクロになるのかな
413 名前:デフォルトの名無しさん mailto:sage [2007/07/08(日) 18:16:20 ] は?
414 名前:デフォルトの名無しさん mailto:sage [2007/07/08(日) 19:57:33 ] 除算命令に出くわして、せっせとメモリ中のコードを書き換える、けなげな86の姿を想像した・・・
415 名前:デフォルトの名無しさん mailto:sage [2007/07/11(水) 22:50:58 ] 言う事聞かない奴隷なんかいらない
416 名前:デフォルトの名無しさん [2007/07/21(土) 07:45:05 ] >>412 マイクロプログラムで処理してるんだろ >8086のマイクロコードは、命令長が21ビットで、プログラムサイズは504ステップであった
417 名前:デフォルトの名無しさん mailto:sage [2007/07/21(土) 10:07:54 ] そろそろダンゴさんに〆てもらうか。
418 名前:デフォルトの名無しさん mailto:sage [2007/07/21(土) 21:50:22 ] うむ
419 名前:デフォルトの名無しさん [2007/08/03(金) 07:04:32 ] あ
420 名前:デフォルトの名無しさん mailto:sage [2007/08/03(金) 11:40:01 ] ダゴンを深淵から呼びだしては駄目だ
421 名前:だんごの輪島 [2007/08/03(金) 12:15:43 ] ん?
422 名前:デフォルトの名無しさん mailto:sage [2007/08/03(金) 21:06:03 ] は?
423 名前:デフォルトの名無しさん [2007/08/12(日) 09:53:59 ] は
424 名前:デフォルトの名無しさん mailto:sage [2007/08/12(日) 10:01:53 ] ビッチ演算
425 名前:デフォルトの名無しさん mailto:sage [2007/08/12(日) 14:27:31 ] ビット大佐
426 名前:デフォルトの名無しさん [2007/08/14(火) 10:07:39 ] age
427 名前:デフォルトの名無しさん mailto:age [2007/08/14(火) 11:48:05 ] あ
428 名前:デフォルトの名無しさん mailto:sage [2007/08/16(木) 20:39:50 ] 〆
429 名前:デフォルトの名無しさん [2007/08/18(土) 23:05:50 ] あgw
430 名前:デフォルトの名無しさん mailto:sage [2007/08/18(土) 23:09:42 ] ぬるぽ
431 名前:デフォルトの名無しさん [2007/08/20(月) 01:29:30 ] ちょっとスレの趣旨と違うと思うんだけど、適当なところが無かったので、 アドバイス頼む。 アドレスのアライメントをチェックするためにポインタをintにキャストして &でビットテストしてる。 extern char *p; if(((int)p & 3) == 0){ //32bit境界にある処理… } だけどアドレスをintにキャストするのは64bit時代的に行儀悪いみたい。 でもアドレスをビットテストしたいという状況は普通にあると思うんで、 こういう場合C系的にはどう書くのが上手な作法なの?
432 名前:デフォルトの名無しさん mailto:sage [2007/08/20(月) 01:38:30 ] >>431 Linux界隈じゃ unsigned long へのキャストが一般的とされてるが 個人的には嫌い
433 名前:デフォルトの名無しさん mailto:sage [2007/08/20(月) 01:40:50 ] intptr_t / uintptr_t を使えばいいんじゃない?
434 名前:デフォルトの名無しさん mailto:sage [2007/08/20(月) 08:48:31 ] 下位ビットだけ入ればいいので、charでもいい
435 名前:デフォルトの名無しさん mailto:sage [2007/08/20(月) 23:58:10 ] さすがにそれはありえないだろ?
436 名前:デフォルトの名無しさん mailto:sage [2007/08/21(火) 00:11:51 ] なぜそう思うの?
437 名前:デフォルトの名無しさん mailto:sage [2007/08/21(火) 00:33:14 ] バイトオーダー
438 名前:デフォルトの名無しさん mailto:sage [2007/08/21(火) 00:37:00 ] バイトオーダーは関係ないかと
439 名前:・∀・)っ-○◎● mailto:sage [2007/08/21(火) 00:52:14 ] WindowsならUINT_PTRにキャスト
440 名前:デフォルトの名無しさん mailto:sage [2007/08/21(火) 01:00:01 ] ダンゴさんがピシっと〆めたな。
441 名前:・∀・)っ-○◎● mailto:sage [2007/08/21(火) 01:19:06 ] うんこうんこうんk
442 名前:デフォルトの名無しさん [2007/09/09(日) 23:01:40 ] う
443 名前:デフォルトの名無しさん [2007/09/09(日) 23:35:23 ] ん
444 名前:デフォルトの名無しさん mailto:sage [2007/09/09(日) 23:37:25 ] ち
445 名前:デフォルトの名無しさん [2007/09/09(日) 23:45:20 ] ゃ
446 名前:デフォルトの名無しさん [2007/09/16(日) 06:34:05 ] あ
447 名前:デフォルトの名無しさん mailto:sage [2007/09/19(水) 12:28:31 ] は
448 名前:デフォルトの名無しさん mailto:sage [2007/09/19(水) 12:32:11 ] た
449 名前:デフォルトの名無しさん mailto:sage [2007/09/19(水) 13:50:16 ] ぼ
450 名前:デフォルトの名無しさん mailto:sage [2007/09/19(水) 23:03:56 ] ぬ
451 名前:デフォルトの名無しさん mailto:sage [2007/09/19(水) 23:56:29 ] る
452 名前:デフォルトの名無しさん [2007/09/20(木) 00:04:43 ] ぽ
453 名前:デフォルトの名無しさん mailto:sage [2007/09/20(木) 18:42:49 ] >>450-452 ガ
454 名前:デフォルトの名無しさん mailto:sage [2007/09/22(土) 00:43:27 ] pc11.2ch.net/test/read.cgi/tech/1142467359/555 これもっと簡単にならないかな?
455 名前:デフォルトの名無しさん mailto:sage [2007/09/22(土) 07:06:58 ] >>454 -------------------- int my_fputwc(wint_t c, FILE *fp) { wint_t r = fputwc(c, fp); return (r == WEOF) ? EOF : r; } int wtbl[0x10000]; void dokkade_jikkou(void ) { int i; for (i = 0; i < 0x10000; i++) wtbl[i] = i; wtbl[0xffff] = EOF; } int my_fputwc(wint_t c, FILE *fp) return wtbl[fputwc(c, fp);]; } みたいなこと(WEOF(wint_tの0xffff)をEOF(intの-1)に変換) をもっとスマートに行う方法ないですかね。 ---------これで何の不満があるんだ?----------- wtbl[0xffff] = EOF; for (i = 0; i < 0xffff; i++) wtbl[i] = i; } --------------------
456 名前:デフォルトの名無しさん [2007/09/27(木) 20:24:00 ] age
457 名前:デフォルトの名無しさん [2007/09/29(土) 23:03:31 ] int rotate_0_9(int a){a++;return(a+(((a+6)>>4 )+(((a+6)>>4 )<<1))<<1)&15;} or int rotate_0_9(int a){a++;return(a+((a+6)>>4 )*6)&15;} 引数が0〜8の時1を加算し、引数が9の時0を返す。