X



【C++】高速化手法【SSE】2 [転載禁止]©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
0003デフォルトの名無しさん
垢版 |
2015/05/21(木) 02:00:37.40ID:ZhKmhhGS
1スレ10年も掛かったのかwww

compiler intrinsicsの普及と、x64ではインラインアセンブラが使えなくなったのが
またSIMDの再普及に繋がる気がする

SSE3、SSE4、AVX、AVX2、FMAと言った新しい命令も増えているのも理由の一つか
0007デフォルトの名無しさん
垢版 |
2015/05/21(木) 13:51:48.66ID:Jx6BJl3J
マルチコアによるマルチスレッド化の方がずっと楽だから、難しいSIMDプログラミングはいまいち
はやらないのかな
0008デフォルトの名無しさん
垢版 |
2015/05/21(木) 19:18:14.97ID:taVQHAdz
SIMDは作るのは難しいが、一度作ってしまうと、関数の中に封じ込めることが出来るので、
後からの使い勝手自体はマルチスレッドよりも良いんだがな。ライブラリ化もただの関数なので問題ない。
マルチスレッドだと関数の中だけで閉じなくて、アプリ全体の設計の部分まで話が広がるので、
機能単位でライブラリ化するのが難しく、簡単に使いまわせない。
ま、SIMDはライブラリ化しやすいから、多くのものが既にライブラリ化されてて、
ほとんどの人はそれを使うだけですむので、自分で書く必要性が少なくて、
故に過疎りやすいってのもあると思うがね。
0009デフォルトの名無しさん
垢版 |
2015/05/21(木) 19:30:58.21ID:Ao5A+4wF
SIMD化はコンパイラに任せるのが得策。
アルゴリズム改善がどこもできなくなってからでいい。
0010デフォルトの名無しさん
垢版 |
2015/05/21(木) 20:29:21.14ID:taYfOZ7g
前スレの8bit単位の乗算とか、そういう頻繁にありそうなケースに対応した命令を用意してくれないと、
間口広がんないよ・・・。
0011デフォルトの名無しさん
垢版 |
2015/05/21(木) 20:45:29.77ID:2/488D5d
8/16bitぐらいのIndex範囲でテーブル引きしれくれる命令がほしいわ

8bit演算するにも無駄なシャッフルしなくても良い命令がそろったのがSSE4辺りで
さらにAMDが未対応みたいな期間長すぎたな
0012デフォルトの名無しさん
垢版 |
2015/05/22(金) 01:51:48.18ID:pqX01hMi
命令に対応してたってそれを実行するユニットがそれ相応に強化されてなければ大して効果ないよ
0013デフォルトの名無しさん
垢版 |
2015/05/23(土) 18:03:12.07ID:1SFlVJvM
並列計算が実装されてないか、使っても遅いとき、通常の演算で並列できないか?

(a0 + a1X + a2X^2 + a3X^3) ( s + tX) のXの1乗、3乗を取り出すことで、
0014デフォルトの名無しさん
垢版 |
2015/05/23(土) 18:08:24.46ID:1SFlVJvM
途中送信した。
上のXの項は、t a0 + s a1
上のX^3の項は、t a2 + s a3

Xをたとえば2^10や2^16と取り、下位からの桁上りがないとすると、ビット演算でデータ取り出せる。
0015デフォルトの名無しさん
垢版 |
2015/05/23(土) 19:52:22.42ID:1SFlVJvM
>>13>>14を実装して並列計算の叩き台を作った。微妙に速度アップした。結果が正しくないが計算量は正しいはず。

#include <iostream>
#include <time.h>
using namespace std;
#define N (1<<18)
void initdata(unsigned char *a, int range){ for(int n=0; n<2*range; n+=2) { a[n]=rand()%256; a[n+1]=rand()%256; }}

#define cal(x,y,s) {x=(x*s + y*(255-s))&255; y=(y*s + x*(255-s))&255;}
void test(unsigned char *a) {
for(int n=0; n<2*N; n+=2) {
unsigned char x=a[n], y=a[n+1];
for(int s=1; s<255; s++) cal(x,y,s); for(int s=1; s<255; s++) cal(x,y,s); for(int s=1; s<255; s++) cal(x,y,s); for(int s=1; s<255; s++) cal(x,y,s);
a[n]=x; a[n+1]=y; }}

// (a0 + a1X + a2X^2 + a3X^3) ( 255-s + sX) Xの項は、s*a0 + (255-s)*a1 X^3の項は、s*a2 + (255-s)*a3
#define dset(x,y) (x) + ((y)<<8) + ((y)<<16) + ((x)<<24);
#define cal2(x,s) { x *= ( s + ((255-s)<<8) ); unsigned char c=(x>>8)&255, d=(x>>24)&255; x = dset(c,d); }
void test2(unsigned char *a) {
for(int n=0; n<2*N; n+=2) {
unsigned int x = dset(a[n], a[n+1]);
for(int s=1; s<255; s++) cal2(x,s); for(int s=1; s<255; s++) cal2(x,s); for(int s=1; s<255; s++) cal2(x,s); for(int s=1; s<255; s++) cal2(x,s);
a[n]=(x>>8)&255; a[n+1]=(x>>24)&255; }}

int main() {
unsigned char *a = new unsigned char [2*N],*b = new unsigned char [2*N];
initdata(a, N); memcpy(b,a,2*N);
cout<<"memcmp(a,b):"<<(memcmp(a,b,2*N)?"false":"true")<<endl;
unsigned long t=clock(); test(a); t=clock()-t; cout<<t<<endl;
t=clock(); test2(b); t=clock()-t; cout<<t<<endl;
cout<<"memcmp(a,b):"<<(memcmp(a,b,2*N)?"false":"true")<<endl;
return 0; }
0016デフォルトの名無しさん
垢版 |
2015/05/27(水) 11:09:42.07ID:f/0uemgN
前スレ終わりごろのビットマップ合成の話だが、結果的にはスカラ版と比較して
5倍程度に収まっていたが、初期はスカラ版より遅い結果しか出せていなかった。
スカラ版と等速なら話はわかるが、
なぜ遅くなるのか?
俺も似たようなこと遭遇した記憶はあるが
詳細が思い出せない。
0017デフォルトの名無しさん
垢版 |
2015/05/27(水) 13:45:50.89ID:2yaRNWB+
SIMD関連はまず命令の実行に都合のいいようにデータを作成するのと
結果を取り出すのに時間がかかるからじゃね?
それとSSEレジスタは128bitなので1処理当たり32bit使うと4並列にしかならない
AVX/AVX2なら256bitなのでこちらの方が速度が上がると思う
0018デフォルトの名無しさん
垢版 |
2015/05/27(水) 15:22:12.59ID:TYkQbksz
>>16
構造体へのコピーをスカラで何倍もの時間かけてやってたから
本体処理が4秒が1秒に縮まったところでセットアップに5秒かかってたら意味がない

ボトルネックを解消するつもりでSIMDを使ったつもりが新たな別のボトルネックを作ってました
しかもなんで遅くなったのか使った本人が認識してないというの。
0019デフォルトの名無しさん
垢版 |
2015/05/27(水) 18:10:04.45ID:1+NR3ImF
つまりSIMDレジスタで計算する為に
スカラ以上に命令を使った為
遅くなったということか。
前スレの968では見直ししたが2倍ほど遅いと言っていた。
本来4倍になるはずが1/2倍、
8倍も遅くなるなんてありえるか?
根本的に何か問題があるとしか
思えん。
0020デフォルトの名無しさん
垢版 |
2015/05/27(水) 19:09:25.21ID:VZ6+fhUn
あんなのソースコード見ればボトルネックがどこにあるか一発でわかるだろ
見ただけでわからんやつは向いてないよ
0021デフォルトの名無しさん
垢版 |
2015/05/27(水) 19:11:41.34ID:VZ6+fhUn
「ハッカーのたのしみ」とかの良著をよく読むことをすすめるよ
並列化アルゴリズムに理解のないやつがいきなりSSEやAVX使っても不幸にしかならない
0022デフォルトの名無しさん
垢版 |
2015/05/27(水) 19:52:40.39ID:21LcoVTJ
然しものSIMDも、まったくオーバーヘッドがないわけじゃぁない。
SIMDに演算させるためのデータ構造整えなんかの命令分がオーバーヘッドになる。
これを最小に抑えつつ、SIMDの並列演算性能を活かすのが腕の見せ所よ。
0023デフォルトの名無しさん
垢版 |
2015/05/29(金) 18:33:22.93ID:5gPBcsmJ
メモリクソ余ってんだから最初からSIMD前提なデータ構造強制できりゃいいのになぁ
0024デフォルトの名無しさん
垢版 |
2015/06/08(月) 22:06:48.16ID:XUgdS8pG
すいません。以下のようなことがやりたいのですがどうするのが一番いいですか。

void up_index(short a[16],short b[16])
{
0025デフォルトの名無しさん
垢版 |
2015/06/08(月) 22:12:29.64ID:XUgdS8pG
すいません。途中で書き込みました。
avx2でお願いします。

void up_index(short a[16],short b[16])
{
for(int i=0;i<15;i++)
{
b[i]=a[i+1];
}
b[15]=0;
}

void down_index(short a[16],short b[16])
{
b[0]=0;
for(int i=1;i<16;i++)
{
b[i]=a[i-1];
}
}
0026,,・´∀`・,,)っ-○○○
垢版 |
2015/06/08(月) 22:54:29.21ID:GQ7FFrMa
void up_index(short a[16],short b[16])
{
__m256i mask = _mm256_setr_epi16(
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0x0000
);
__m256i x = _mm256_loadu_si256((__m256i*)a[1])
x = _mm256_and_si256(x, mask);
_mm256_storeu_si256((__m256i*)b, x);
}

あとわかるよな?
0028デフォルトの名無しさん
垢版 |
2015/06/08(月) 23:02:02.79ID:XUgdS8pG
>>__m256i x = _mm256_loadu_si256((__m256i*)a[1])
領域外(a[16])を参照してるような…
ゴミが入るだけだから気にしなくていいってことですか?
0029デフォルトの名無しさん
垢版 |
2015/06/08(月) 23:58:10.30ID:XUgdS8pG
うごいてるっぽいので気にしないことにします。
ありがとうございました。
003125
垢版 |
2015/06/09(火) 00:47:54.26ID:8QWNG3PG
>>ページ境界跨がなきゃ平気
跨ぐとどうなるんでしょうか。
突然プログラムがあぼーんすることも覚悟しなきゃいけないってことですか?
0033デフォルトの名無しさん
垢版 |
2015/06/09(火) 02:26:12.65ID:+xTmfGgc
https://software.intel.com/sites/products/documentation/doclib/iss/2013/compiler/cpp-lin/GUID-F4DA723A-DEB9-42D8-82FF-72553EB24273.htm

ここによるとアラインされてなくてもいけるcompiler intrinsicsだわな
アラインが必要なのは

https://software.intel.com/sites/products/documentation/doclib/iss/2013/compiler/cpp-lin/GUID-29CB35FA-F50D-4F6E-88B6-D3A1D83BE311.htm

こっちの方だ
_mm256_load_si256()

ただ当然境界がズレている所は2回ほど読むだろうから速度を気にするのなら
最初から_mm256_load_si256()を使ってデータの配置もアライメント通りにしとくのに限る

配列だと__attribute__((aligned(16)))を付けて置くといいわな
0035デフォルトの名無しさん
垢版 |
2015/06/09(火) 08:01:24.58ID:uvrBn2pL
別にアライメントの話じゃないし。
つうか領域外読み込んでも
落ちないからOKとか
それはないから
0036,,・´∀`・,,)っ-○○○
垢版 |
2015/06/09(火) 10:18:10.60ID:hpY+QnAE
上下128ビット跨いだシフトが簡単にできないから
ミスアラインロード使わないとめんどくさいんだよねー

void up_index(short a[16],short b[16])
{
  __m256i x = _mm256_load_si256((__m256i*)a);
  __m128i u = mm_mm256_extracti128_si256(x, 1);
  x = _mm256_alignr_epi8( x, _mm256_castsi128_si256(u), 14);
  _mm256_store_si256((__m256i*)b, x);
}
003825
垢版 |
2015/06/09(火) 21:40:12.66ID:8QWNG3PG
16 x 16 だと結構オーバヘッド覚悟しなきゃいけないみたいですね。
11 x 11 なら128ビットに納まるから上下左右1ビットシフト高速にできますかね?
0039,,・´∀`・,,)っ-○○○
垢版 |
2015/06/09(火) 21:47:54.51ID:X9YqiuVE
ビットボードでも作ってるの?

11ビットとかかえって扱いづらいからやめとき?pslldq/psrldqは8ビット単位だからいろいろ面倒だぞ
16x16でもvextractf128+vpalignrの2命令ですむんんだからそれが一番無難
2のべき乗のほうが扱いやすい
0041デフォルトの名無しさん
垢版 |
2015/06/09(火) 21:55:17.24ID:8QWNG3PG
>>39
はい、まさにビットボードです。
9 x 9 あれば囲碁9路盤が作れます。
やっぱ2のべき乗ですかね〜。
0042デフォルトの名無しさん
垢版 |
2015/06/09(火) 22:00:22.26ID:uvrBn2pL
SIMDとか並列プログラムは
各要素間の関連が薄けりゃ薄いほど良い
相関ゼロなら100%の性能が出せるが
逆なら劣化する。
要はお前のプランはSIMD向きじゃねえんだよ。
スカラで組めカス。
0044,,・´∀`・,,)っ-○○○
垢版 |
2015/06/09(火) 22:34:23.52ID:ftbXeVKR
上下128ビットの入れ替えが面倒なら、1レジスタで1ボードじゃなくて2レジスタで2ボードみたいな割り当てもアリかな
0046デフォルトの名無しさん
垢版 |
2015/06/11(木) 17:55:12.67ID:6lVnkCXZ
1レジスタに1ボードのらないで2レジスタに2ボードのる状況が想像できない。
0047,,・´∀`・,,)っ-○○○
垢版 |
2015/06/11(木) 21:11:39.78ID:ucI+50Qq
me too

碁盤の19x19なら1列32ビットに割り当てて128ビットの4x5レジスタじゃいかんのか?
256ビットなら3レジスタか。ちと苦しいな
0049デフォルトの名無しさん
垢版 |
2015/06/13(土) 04:02:16.52ID:0MXVYW8Q
さて、そろそろ団子が実験結果を公開してくれる頃だと思うんだが……
ソース書けた?
0051デフォルトの名無しさん
垢版 |
2015/06/22(月) 09:21:43.06ID:0p5/VSpX
結局SSEとかの機械語でやる以外にC++には高速化の手段がないの?(´・ω・`)
後、変なclassを使わないとか?(´・ω・`)
0052デフォルトの名無しさん
垢版 |
2015/06/22(月) 16:45:31.61ID:BEzC3Nfs
クラスで遅くなるとか迷信でしょ
0053デフォルトの名無しさん
垢版 |
2015/06/22(月) 16:51:45.79ID:cpn0Yuio
今はSIMDがあるから
かろうじてC++使ってるけど
他で行けるようになったら
捨てると思う
0054,,・´∀`・,,)っ-○○○
垢版 |
2015/06/22(月) 16:56:25.34ID:h2li5DGU
クラスを使うから遅くなるんじゃなくて、動的なポリモーフィズムを実現するための仮想関数テーブルや
あるいは過剰にコンストラクタ呼び出しで遅くなる。
0056デフォルトの名無しさん
垢版 |
2015/06/22(月) 19:59:05.05ID:cpn0Yuio
いやーそんなん無いけどさー
己が納得出来れば良い訳よ
vector4クラスとかあって
最適化コンパイルでSIMD使いますよ〜
で良い。所詮趣味だし俺はそれで乗り換え出来る。
今はfortranやC++以外にはそれすらも無いからな
0057,,・´∀`・,,)っ-○○○
垢版 |
2015/06/22(月) 20:04:38.95ID:L2Qxnu5O
過度なオブジェクト指向(笑)やめればC++でもアセンブラに迫る高効率のコード書けますよ
0058デフォルトの名無しさん
垢版 |
2015/06/22(月) 21:19:49.22ID:468RGWDu
最近はCとアセンブラを比較することも少なくなったろうな。
数学ライブラリなんかはまだアセンブラで書いてんのかねぇ。
0060,,・´∀`・,,)っ-○○○
垢版 |
2015/06/22(月) 23:15:07.42ID:OAaA5v1W
演算子オーバーロードやテンプレートがCにあるならそうだね
どの程度の抽象化までならオーバーヘッドが生じないかはdvec.hあたりのIntel謹製クラスライブラリ見ればわかるでしょ
0061マ○コデラックス
垢版 |
2015/06/23(火) 23:58:04.32ID:bwjeXC/X
スレ立てるまででもない質問じゃない質問ってどんなの?
0062デフォルトの名無しさん
垢版 |
2015/06/26(金) 04:43:42.68ID:1ST1aZRQ
え?そこらへん使ってもアセンブラに迫る高効率のコード吐き出してくれるの?
0064デフォルトの名無しさん
垢版 |
2015/06/26(金) 13:07:25.04ID:KiE+sAI+
>>62
C にはない C++ のオーバーヘッドは、例外と仮想関数呼び出しのための関数テーブルアクセスと dynamic_cast<>()。
それらを使わなければ、型チェックの厳しい C として使える。
演算子オーバーロードは変な名前の関数を呼び出してるだけ。
コンストラクタとか(非仮想)デストラクタは C で同じ作法で作ったのと一緒。

最適化で言うと、俺の環境だと this を restrict として扱わないので、
this->func() を func( this ) にするとか人力で最適化されやすくしないといけないことがある。
0066,,・´∀`・,,)っ-○○○
垢版 |
2015/06/26(金) 23:08:38.05ID:Tf/lkRBh
あとはMSVCだとthisポインタをECXで渡すけどSSE*ってECXを暗黙にdestinationとして扱う命令あるじゃん
0069デフォルトの名無しさん
垢版 |
2015/07/04(土) 20:23:55.16ID:g1Tiw5j6
githubってよく知らないんだよなぁ。
イケてるギークはつかってるらしいが。
これを機にやってみるか…
0070 ◆kXDiHQuNQ2
垢版 |
2015/07/04(土) 22:33:31.72ID:g1Tiw5j6
http://www.age2.tv/rd05/src/up9736.zip.html

githubはとりあえず置いといて、ソースうpします。
物は囲連星というゲームの9路盤のAIです。

makefileが入ってるのでbenchmark.exeをmakeしてみてください。
うちのPC(core i7 4790)で40秒くらいで終わるベンチマークができます。
ベンチの内容はAIが3手プレイします。

SSE2で最適化したいクラスはPointSetというクラスで、
128bitつかって 10 x 10 のビットボードを実装しています。

SSE2化してみましたが速くなりませんでした。

スレの皆さん最適化よろしくお願いします。
0071デフォルトの名無しさん
垢版 |
2015/07/04(土) 22:42:47.73ID:YeWNQkLW
SSEって最適化できてもせいぜい20%アップ程度の気がするな。
アルゴリズムの見直しとか、CPU演算以外とかはやりきってるか?
0072デフォルトの名無しさん
垢版 |
2015/07/04(土) 22:49:03.16ID:g1Tiw5j6
ちなみにmakefileは依存関係全然考慮してないので毎回クリーンしてくださいw
コンパイラは64bit MinGWです。
0073デフォルトの名無しさん
垢版 |
2015/07/04(土) 22:51:51.53ID:g1Tiw5j6
オッとリロードしてなかった。
>>71
アルゴリズム見直しで速くなるのが一番いいんですけどね〜
なかなかアイディアが湧かないのでとりあえず手っ取り早いSSEを試してみたいです。
0074デフォルトの名無しさん
垢版 |
2015/07/04(土) 23:13:48.96ID:+CPi2s1F
>>73
i7 4790ならAVX2やiGPGPUで速くしたほうがいいんじゃないのか?
データ並列に適していないのにSIMDにしてもたいして速くならないと思うけど
いまの適している?
0075デフォルトの名無しさん
垢版 |
2015/07/04(土) 23:23:18.20ID:g1Tiw5j6
128bitで一つのビットボードになっていてもろandとかorとかandnotとかさせるので
SSE2で速くなるかなと思ったんですが。
AVX2は256bitですよね?どうやって適応させるか難しいです。
iGPGPUは使い方しらないorz
0076デフォルトの名無しさん
垢版 |
2015/07/04(土) 23:28:34.72ID:Ika70OGI
iGPGPUとか全然ダメ。
並列処理向きな処理でも激遅。
最低でもメモリ空間共有がサポートされなきゃゴミ。
0077デフォルトの名無しさん
垢版 |
2015/07/05(日) 01:38:21.45ID:U8xf2vl9
>>70はピンポイントでSSE化したい所、出来そうな所だけピックアップしてくれよ。
これでは解析が手間。
0079 ◆kXDiHQuNQ2
垢版 |
2015/07/05(日) 08:14:07.41ID:rj88vDKP
>>77
SSE化できそうなところはPointSetというクラスですが、
じつはもうSSE化してます。
でも速くなんなかった。

なぜ速くならなかったか教えていただけると助かります。

>>78
PointSetボトルネックになってないんですかね。
結構使ってるはずなんですが。
0080,,・´∀`・,,)っ-○○○
垢版 |
2015/07/05(日) 08:44:17.99ID:5Fixj9dP
関数ごとのプロファイルとってみて総実行時間を見てみるといいよ
並列化できない(と思ってる)ところが最大のボトルネックになってるなら他をいじってもどうしようもない
0084デフォルトの名無しさん
垢版 |
2015/07/05(日) 10:50:19.25ID:rj88vDKP
ビットフィールドの立ってるビット数える関数をSSE4.2のpopcnt使ったらえらい速くなったんだが?
0087デフォルトの名無しさん
垢版 |
2015/07/05(日) 11:49:59.66ID:pEwkWnHA
ちょっと伺いたいんですがavxまでで8bit(1byte)の中で上半分、下半分を取り出すのはありますか?
avx2までいくとpextというmaskをとった部分のビットだけ抽出するのはあるようなんですが・・・
0088デフォルトの名無しさん
垢版 |
2015/07/05(日) 13:52:49.93ID:TGTnUn4r
pextというとBMI2かね
汎用レジスタでの話ならシフトとandじゃダメな理由があるのかね
連続したnビットを取り出したいだけならレイテンシの長い(3clk)pextを使う価値があまりない

mov eax, 0fh
mov edx, f0h
pext eax, esi, eax
pext edx, esi, edx
5クロック

mov eax, esi
mov edx, esi
shr edx, 4
and eax, 0fh
and edx, 0fh
3クロック、movが消えるなら2クロック
0091デフォルトの名無しさん
垢版 |
2015/07/05(日) 14:43:20.51ID:pEwkWnHA
>>90
ちょうどこんな感じです!
このソースみたいにlowerとupperを取り出して返す関数つくろうと思ってました

下4bitはそのまま0xfでmaskして、上4bitは4bitシフトしてからmaskなのでこのコードで行けそうです
ありがとうございます
0094デフォルトの名無しさん
垢版 |
2015/07/05(日) 16:55:23.92ID:pEwkWnHA
いえアセンブリがわからないだけです!
>>92でいけるのならやってみます!ありがとうございます!
0095デフォルトの名無しさん
垢版 |
2015/07/05(日) 17:09:15.78ID:rj88vDKP
gprofの結果ビットボードを座標のベクタに変換する関数PointSet::toVector()が時間かかってることが分かった。
すまん、ちょっと飯食ってくる。
0096デフォルトの名無しさん
垢版 |
2015/07/05(日) 17:14:58.64ID:7niimHYF
大概は思わぬところでサイクルを食ってるもんだ。
食うのは飯だけにしたいものだな。
0097デフォルトの名無しさん
垢版 |
2015/07/05(日) 19:12:24.15ID:rj88vDKP
PointSet::toVector()は一回最適化試みた箇所なんだよなぁ
正直これ以上アイディアうかばん。
0098デフォルトの名無しさん
垢版 |
2015/07/05(日) 19:48:59.00ID:U8xf2vl9
なにをしてるか知らないがここが時間食ってる。
8ビットや16ビットで区切って計算結果を配列に入れといて利用するとかできないか?


int size()const
{
int res=0;
unsigned long long i;
i = u.table[0];
while (i)
{
++res;
i = (i - 1)&i;
}
i = u.table[1];
while (i)
{
++res;
i = (i - 1)&i;
}
return res;
}
0099デフォルトの名無しさん
垢版 |
2015/07/05(日) 19:54:28.58ID:U8xf2vl9
あとここも。
32bitでの実行だが。


int get(Point p)const
{
// return !((*this) & x_line[p.x()] & y_line[p.y()]).empty();
return (table[p.y() & 1] >> (p.x() + (p.y() >> 1) * 10)) & 1;
}
■ このスレッドは過去ログ倉庫に格納されています

ニューススポーツなんでも実況