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
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を返す。
458 名前:デフォルトの名無しさん mailto:sage [2007/09/29(土) 23:17:24 ] return ++a%9;
459 名前:デフォルトの名無しさん mailto:sage [2007/09/29(土) 23:39:43 ] % はビット演算じゃないだろう
460 名前:デフォルトの名無しさん mailto:sage [2007/09/29(土) 23:58:36 ] int rotate_0_9(int a){return a<9?a+1:0;}
461 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:06:34 ] DAA
462 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:15:35 ] >>457 >>458 >>460 どれが速い?
463 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:20:18 ] 実測あるのみ
464 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:34:05 ] 試してみた! cl /O2 rot9.c rot9 rotate_0_9_457_1 1873 msec rotate_0_9_457_2 1272 msec rotate_0_9_458 4016 msec rotate_0_9_460 641 msec >>460 が圧倒的だった(俺もそう思ってた) ソースに続く
465 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:34:50 ] >>464 のソース (VC6SP4) ---------------------------- #include <windows.h> #include <stdio.h> int rotate_0_9_457_1(int a){a++;return(a+(((a+6)>>4 )+(((a+6)>>4 )<<1))<<1)&15;} int rotate_0_9_457_2(int a){a++;return(a+((a+6)>>4 )*6)&15;} int rotate_0_9_458(int a){return ++a%9;} int rotate_0_9_460(int a){return a<9?a+1:0;} //#define COUNT_TIMES 0x7fffffff #define COUNT_TIMES 0x7ffffff #define TEST(func) \ dwTime = GetTickCount(); \ for(i = 0, count = 0; count < COUNT_TIMES ; count++) { \ i=func(i); \ } \ printf( # func " %d msec\n", GetTickCount() - dwTime); main() { int i, count; DWORD dwTime; SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); Sleep(100); TEST(rotate_0_9_457_1) Sleep(100); TEST(rotate_0_9_457_2) Sleep(100); TEST(rotate_0_9_458) Sleep(100); TEST(rotate_0_9_460) return 0; } ----------------------------
466 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:38:34 ] printf( # func " %d msec (i:%d)\n", GetTickCount() - dwTime, i); と変更して計算結果も表示してみたら>>457 の最初の式の結果がおかしい事に 気付いたんだけど。 rotate_0_9_457_1 1862 msec (i:0) rotate_0_9_457_2 1272 msec (i:7) rotate_0_9_458 3986 msec (i:7) rotate_0_9_460 671 msec (i:7)
467 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:40:00 ] int rotate_0_9_467(int a){ static int t[10]={1,2,3,4,5,6,7,8,9,0}; return t[a]; } 表引き。 これもやってみてくれ。
468 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:49:01 ] >>457 やってみるよ。 457_1のiの推移 0 2 6 14 4 10 12 0 2 6 14 4 10 12 0 2 6 14 4 10 12 0 2 6 14 無茶苦茶だった。
469 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:55:09 ] rotate_0_9_457_1 1893 msec (i:0) rotate_0_9_457_2 1272 msec (i:7) rotate_0_9_458 3996 msec (i:7) rotate_0_9_460 661 msec (i:7) rotate_0_9_467 621 msec (i:7) テーブル引きのがわずかに速いね。 >>460 と>>467 が微差だったんでカウンタ倍にしてみた。 #define COUNT_TIMES 0xfffffffに変更。 rotate_0_9_457_1 3535 msec (i:2) rotate_0_9_457_2 2553 msec (i:5) rotate_0_9_458 7991 msec (i:5) rotate_0_9_460 1332 msec (i:5) rotate_0_9_467 1202 msec (i:5) 計ったPCはThinkPad X31 (PenM1.6G Banias) XPSP2
470 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 00:57:00 ] あと>>458 は0〜8の繰り返しで条件が違うんで int rotate_0_9_458(int a){return ++a%10;} に修正してる
471 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 01:13:29 ] _rotate_0_9_457_2 PROC NEAR ; 13 : int rotate_0_9_457_2(int a){a++;return(a+((a+6)>>4 )*6)&15;} mov ecx, DWORD PTR _a$[esp-4] inc ecx lea eax, DWORD PTR [ecx+6] sar eax, 4 lea eax, DWORD PTR [eax+eax*2] lea eax, DWORD PTR [ecx+eax*2] and eax, 15 ret 0 _rotate_0_9_457_2 ENDP 掛け算消えるんだね _rotate_0_9_458 PROC NEAR ; 14 : int rotate_0_9_458(int a){return ++a%10;} mov eax, DWORD PTR _a$[esp-4] mov ecx, 10 inc eax cdq idiv ecx mov eax, edx ret 0 _rotate_0_9_458 ENDP 見るからに遅そうな
472 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 01:16:44 ] _rotate_0_9_460 PROC NEAR ; 15 : int rotate_0_9_460(int a){return a<9?a+1:0;} mov eax, DWORD PTR _a$[esp-4] cmp eax, 9 jge SHORT $L53312 inc eax ret 0 $L53312: xor eax, eax ret 0 _rotate_0_9_460 ENDP 普通だね _rotate_0_9_467 PROC NEAR ; COMDAT mov eax, DWORD PTR _a$[esp-4] mov eax, DWORD PTR _?t@?1??rotate_0_9_467@@9@9[eax*4] ret 0 _rotate_0_9_467 ENDP 短いね この短さがテーブル参照のオーバーヘッドを相殺してる? けどaが10以上だったら脂肪
473 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 01:27:47 ] まあ表引きはキャッシュから外れた時にペナルティがあるから 平均的には>460がいいんだろうな。
474 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 02:05:05 ] >>473 確かに、別の環境だと逆転してたり。 #Celeron 430@2.4G XPSP2 rotate_0_9_457_1 1750 msec (i:2) rotate_0_9_457_2 1359 msec (i:5) rotate_0_9_458 2969 msec (i:5) rotate_0_9_460 719 msec (i:5) rotate_0_9_467 860 msec (i:5) #Core2Duo 4300@3.2G XPSP2 rotate_0_9_457_1 1281 msec (i:2) rotate_0_9_457_2 1000 msec (i:5) rotate_0_9_458 2172 msec (i:5) rotate_0_9_460 516 msec (i:5) rotate_0_9_467 656 msec (i:5)
475 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 04:40:29 ] %は割り算があるから遅いってことか。0〜9ではなく0〜2^n-1の場合にかぎり使えばいいかな。 でも実際の仕事では0〜99のローテートでも%で書いたりするなあ。
476 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 08:29:40 ] 剰余は定数除算よりも更に遅い。
477 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 09:14:40 ] その剰余をビット演算でなんとか...
478 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 10:11:46 ] このスレの355から、剰余をビット演算でする方法が書かれているよ。 入力が必ず0〜9なら a=((a+7)&15)-6; // 0〜8 が 1〜9 9が-6 (aの符号拡張か 4bitの算術右シフト結果)のビット反転と and
479 名前:457 mailto:sage [2007/09/30(日) 23:43:50 ] ふぬぅ、やっぱ分岐しない上にテーブルも使わない奴は遅いな。
480 名前:デフォルトの名無しさん mailto:sage [2007/09/30(日) 23:45:02 ] 逆に考えて、分岐する上にテーブルも使う奴は・・・ すまん、逆に遅くなりそうだ。
481 名前:デフォルトの名無しさん [2007/10/01(月) 16:44:48 ] modも内部的には分岐してるだろ。RISCならよくわかる。
482 名前:デフォルトの名無しさん mailto:sage [2007/10/01(月) 17:41:59 ] え〜(*o*) それは2のn乗の場合とそうでないので分けてるとか?
483 名前:ヽ・´∀`・,,)っ━━━━━━┓ mailto:sage [2007/10/04(木) 02:56:19 ] 剰余 = 披除数 − (除数 * 商) 一般的には商と剰余は同時に求めることが可能
484 名前:デフォルトの名無しさん [2007/10/21(日) 17:07:33 ] age
485 名前:デフォルトの名無しさん mailto:sage [2007/10/21(日) 18:36:55 ] 剰余のビット演算への変換ならこのページにあるよ。 www.tensyo.com/urame/date/dayTips.htm#MOD 縛りを入れるともっと高速化出来そう…
486 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 00:23:05 ] ある変数の値が 2018か2019 4049か4050 であるか判別する方法は4回比較するしか ないかな?
487 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 00:49:07 ] 愚直な方法だけど比較2回には減らしてみた。 bool check(int value) { const int mask = ~1; if( (value & mask) == 2018 || ((value + 1) & mask) == 4050 ) return true; return false; }
488 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 01:56:04 ] テストしてないけど。 bool check(int value) { const int mask = ~1; if (((abs(value - 3034) + 1) & mask) == 1016) return true; return false; }
489 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 09:11:06 ] AND も加算も比較=減算も、演算量は同じ、ってこと考えたら、どっちも減ってない。 比較4回に比べてリーダビリティは下がってる。
490 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 09:53:31 ] switch (value) { case 2018: case 2019: case 4049: case 4050: doit(); }
491 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 11:06:26 ] if (v == 2018 || v == 2019 || v == 4049 || v == 4050) return 1; return 0; 0m48.123s 0m2.250s const int mask = ~1; if ((v & mask) == 2018 || ((v + 1) & mask) == 4050) return 1; return 0; 0m53.281s 0m2.278s const int mask = ~1; if (((abs (v - 3034) + 1) & mask) == 1016) return 1; return 0; 0m52.661s 0m2.167s switch (v) { case 2018: case 2019: case 4049: case 4050: return 1; } return 0; 0m46.065s 0m2.087s if (v < 2018 || (v > 2019 && (unsigned int) (v - 4049) > 1)) return 0; return 1; 0m45.938s 0m2.086s いろいろ測ってみた コンパイラやマシンによって違うと思うけど
492 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 11:25:06 ] 4回比較より下の2つのが短いのが不思議ですね。 入力が多数回で、4つの値が均等にバラつくという条件にしたら、最後まで演算しない4回比較 がイイかと思えますが。
493 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 11:26:33 ] >>489 可読性も考慮するの?このスレで?
494 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 11:29:15 ] ちなみに最後の一個はswitchバージョンのアセンブル出力をCに直したもの
495 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 12:45:37 ] iccで試してみた。 # icc -xP -O3 -ip # icc 10.0 上から、0.3, 0.23, 0.33, 0.3, 0.22[sec/(10000 * 10000call)]だった。 どうやらswitchで書いても一番上と同じような出力になるようだ。 gccでも試してみた。 # gcc -O3 -funroll-loops # gcc 3.4.6 こちらは、0.16, 0.22, 0.27, 0.17, 0.22[sec/(10000 * 10000call)]だった。 なんでこんなに速いんだ?w
496 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 21:35:27 ] >>495 アセンブリコードで比較してみると分かるんじゃね?
497 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 23:12:05 ] 俺には>>486 が if(v==2018||v==2019){ }else if(v==4049||v==4050){ }else{ } って条件に読めるんだが
498 名前:デフォルトの名無しさん mailto:sage [2007/10/23(火) 23:17:57 ] 俺も俺も
499 名前:デフォルトの名無しさん mailto:sage [2007/10/24(水) 00:23:34 ] >>486 日本語でおk やっと言う側に回れたか
500 名前:デフォルトの名無しさん mailto:sage [2007/10/24(水) 01:05:28 ] >>497 いや、今日きちんとみかか村に出撃して 糞仕様について問い詰めてきたけど case 2018: case 2019: case 4049: case 4050: で正しい どうもみんなありがとう
501 名前:デフォルトの名無しさん mailto:sage [2007/11/02(金) 19:56:43 ] >491 >if (((abs (v - 3034) + 1) & mask) == 1016) return 1; ここら辺の数値の導き方教えてください どいった関係で3034とか出すの?ど素人ですんません
502 名前:デフォルトの名無しさん mailto:sage [2007/11/02(金) 20:15:08 ] >>501 2018+4050=2019+4049=3034+3034 v = [2018 or 2019 or 4049 or 4050] の時 abs(v - 3034) = [1015 or 1016] abs (v - 3034) + 1 = [1016 or 1017] mask=0xfffffffeより奇数はそれを超えない偶数に変換される。 (abs (v - 3034) + 1) & mask = 1016
503 名前:デフォルトの名無しさん mailto:sage [2007/11/02(金) 21:44:43 ] >502 ものっそい感動しました 久しぶりに成長した気がする この括り方すげー
504 名前:デフォルトの名無しさん mailto:sage [2007/11/03(土) 20:48:03 ] もはや逆方向にソースから動作仕様を求めることはほぼ不可能だな
505 名前:デフォルトの名無しさん mailto:sage [2007/11/04(日) 06:35:34 ] かっこいい BIN→BCD は?
506 名前:デフォルトの名無しさん mailto:sage [2007/11/04(日) 08:47:47 ] 速さなら、00h,01h,02h・・・を表に持ち、binで表引き。 <99のチェックは必要。 サイズなら、((bin/16)<<4) | (bin%16) ・・・バイト版。 <99のチェックは必要。 ワードは、/100の商と余りに分けて、上のを呼び、合成。 自分で書いたのはこんな当たり前の奴だなあ・・・
507 名前:デフォルトの名無しさん mailto:sage [2007/11/10(土) 16:03:38 ] しばらく前はメモリアクセスがからむテーブル参照の方が重いって話だったけど、 また状況変った?
508 名前:デフォルトの名無しさん mailto:sage [2007/11/10(土) 16:47:46 ] キャッシュの容量 メモリアクセス速度とキャッシュアクセス速度の比率 によって変わるからなあ 細かくいいだすとキャッシュ方式も絡むし 結局「場合による」んじゃねえの
509 名前:デフォルトの名無しさん mailto:sage [2007/11/10(土) 17:28:19 ] 一般論としては、キャッシュに載っている(=頻繁に呼ばれる)ならテーブルの方が速いんじゃないかね。 ただ、この場合の「一般」というのは、分岐が含まれる(=分岐ミスの可能性がある)という前提。 例えば上の((bin/16)<<4) | (bin%16) の場合だと 依存関係が2箇所あって、その部分は同時実行は出来ないけど キャッシュアクセスに要する数クロック程度の時間と比べてどちらが速いかはわからんね。 テーブルジャンプ(ほぼ同じ値が続く場合以外)は糞だけど。
510 名前:デフォルトの名無しさん mailto:sage [2007/11/10(土) 17:37:19 ] 掛けたり割ったりすることにものすごい抵抗感がある
511 名前:デフォルトの名無しさん mailto:sage [2007/11/10(土) 18:06:01 ] いや、この場合に限れば、まず間違いなく最適化でシフトやアンドになるよ。