数値計算第2回課題

今回の課題は

1000x1000行列(double)の積を高速に計算するプログラムを作れ。10回別の行列のペアに適用して,平均の計算時間を出せ。尚,自分の計算機環境を示し,最も早い計算時間を出したものは試験を免除する(試験の点の配点分だけ満点をあげる)。

である。締め切りは2週間後(6月2日正午)。

結果の発表

次の5作品を最高速競争の優秀作と認定する。この作品の著者は数値計算の筆記テストは免除し,その配点分満点を出すこととして,栄誉を讃える。尚,以下のファイルはすべてpdfで約200kである。

斎藤卓也君 Pentium4 1.4GHzで1.5秒。ハードなども含めなんでもありで一番であるが,そのテクニックもすごい。

河邊昌彦君 PentumIII 733MHzで4.7秒。結果の検証付。

匂坂岳志君 第4端末室(PentiumIII 800MHz, Redhat Linux 6.2)で4.0秒。

藤井優尚君 第1端末室(PentiumIII 600MHz, VC++)で6.9秒。

牧野知仁君 Celeron 466MHz Dual Processorsで6.4秒(一人しかDual Processorsでのプログラミングをしなかったのでこの分野では一番となった)。

尚,微妙な判定の部分もあるので,自分もこれに匹敵するという場合には,その理由を書いてもう一度レポートを添付してメールすること。理由が正当なら追加で表彰します。(6月2日20;00現在)

また,Matlab6をPentiumIII600MHzで実行したときの同じ内容の計算では4.5秒程度であり,世の中では,この辺が最高値に近い。藤井君の結果でも1.5倍かかっている。

追加の表彰(6月6日)

上での 結果の発表に書いたように,ダントツの結果もあるが,微妙な判定もあったということで自己申告を求めたところ次のような申請がありました。この2件については理由を正当と認め追加で表彰します。これらの作品の著者も数値計算の筆記テストは免除し,その配点分満点を出すこととして,栄誉を讃える。尚,今回は結果が正しいことの検証を求めていなかったため,その辺は緩めにしています。このあたりについては別途講義します。また,追加の表彰も今回で原則としてうち切りたい。

矢島伸吾君(dvi)

申請理由 第一端末室でのプログラムの実行結果は6.47秒でした。 D:\>matrix.exe 6.47 sec 6.47 sec 6.47 sec 6.47 sec 6.48 sec 6.48 sec 6.48 sec 6.48 sec 6.48 sec 6.47 sec average: 6.47 あと、レポートにも記載してあると思いますが、 「アンローリングを行わないプログラム」でも6.8秒台でしたので、 藤井君のプログラムよりも速いです。 (ちなみに、第2端末室での結果は6.89秒でした) 加えて、私のプログラムは ・行列を細分化して計算するとき、コピーを行っていない (単純な6重ループのきれいなコードで計算できる(非アンローリング時) ・値の検証ができるデバッグモードのコードが含まれている という特徴があり、結構いい線いってるのではないか? と思ったので、メールしてみました。 今回の課題は私も楽しかったです。これからも、このような 「個性の出せるプログラミングの課題」を出していただけると うれしいです。

圷 弘明君

第一端末室でまったく同じプログラムをコンパイルし実行した結果です。 1th Calcuration time: 5.818000 280383.402719(-1.235575e+052) 2th Calcuration time: 5.809000 261014.012570(4.432789e+303) 3th Calcuration time: 5.808000 263782.605813(1.213043e+126) 4th Calcuration time: 5.819000 263825.171848(-4.502302e+229) 5th Calcuration time: 5.808000 283343.970602(1.213043e+126) 6th Calcuration time: 5.809000 257281.206741(4.432789e+303) 7th Calcuration time: 5.808000 271508.165292(1.213043e+126) 8th Calcuration time: 5.809000 255266.484038(4.432789e+303) 9th Calcuration time: 5.808000 273070.806140(1.213043e+126) 10th Calcuration time: 5.809000 275261.633756(4.432789e+303) average time: 5.810500 平均計算時間が5.81秒と高速です。再考をお願いします。

数値計算第2回課題 <問題> 行列の乗算A*Bを早くする方法を考えよ。ただし、AとBは1000×1000の行列で、 double型である。

<実験環境> 次のような環境で実行した。 CPU: Pentium3 1Ghz FSB133 メモリ: PC100 CL3 384MB OS: Windows98 SecondEdition コンパイラ: VisualC++6.0 Service Pack 5

<プログラム>  以下のプログラムをコンパイルの最適化オプション /O2 /Ob2 を指定してコンパイルした。

#include #include #include double a[1000][1000],b[1000][1000],c[1000][1000]; main(){ double x,y,z[11],p; int s,t,u,v,s1,u1,s2,u2; for(v = 1; v < 11; v++){ for(s = 0; s < 1000; s++){ for(t = 0; t < 1000; t++){ a[s][t] = (double)(rand() % 1000000)/1000; b[s][t] = (double)(rand() % 1000000)/1000; c[s][t] = 0.0; } } x = clock(); for(u = 0; u < 1000; u+=100){ u2 = u+100; for(s = 0; s < 1000; s+=100){ s2 = s+100; for(t = 0; t < 1000; t+=10){ for(s1 = s; s1 < s2; +){ for(u1 = u; u1 < u2; u1++){ c[s1][u1+0] += (a[s1][t] * b[t][u1+0]) + (a[s1][t+1] * b[t+1][u1]) + (a[s1][t+2] * b[t+2][u1]) + (a[s1][t+3] * b[t+3][u1]) + (a[s1][t+4] * b[t+4][u1]) + (a[s1][t+5] * b[t+5][u1]) + (a[s1][t+6] * b[t+6][u1]) + (a[s1][t+7] * b[t+7][u1]) + (a[s1][t+8] * b[t+8][u1]) + (a[s1][t+9] * b[t+9][u1]); }}}}} y = clock(); z[v] = (y - x)/CLOCKS_PER_SEC; printf("%d", v); printf("th Calcuration time: %lf", z[v]); printf(" %f(%e)\n",c[999][999]); } p = 0; for(t = 1; t < 11; t++){ p += z[t]; } p = p / 10; printf("\n average time: %lf \n\n", p); }

<実行結果> 1th Calcuration time: 3.900000 280383.402719(4.667261e-062) 2th Calcuration time: 3.740000 261014.012570(1.081150e-160) 3th Calcuration time: 3.740000 263782.605813(1.081150e-160) 4th Calcuration time: 3.740000 263825.171848(1.081150e-160) 5th Calcuration time: 3.730000 283343.970602(9.458745e-013) 6th Calcuration time: 3.730000 257281.206741(9.458745e-013) 7th Calcuration time: 3.740000 271508.165292(1 .081150e-160) 8th Calcuration time: 3.740000 255266.484038(1.081150e-160) 9th Calcuration time: 3.790000 273070.806140(-5.164703e-284) 10th Calcuration time: 3.730000 275261.633756(9.458745e-013) average time: 3.758000  10回繰り返した平均実行時間は3.758秒であった。時間の横に表示されてるのは 実行結果のc[999][999]の値である。また、デフォルトのコンパイルオプションで実 行した結果は、9.88秒であった。何も工夫しないプログラムを最適化オプション/O2 /Ob2でコンパイルすると、実行結果は9.01秒で、また、行列乗算高速化プロジェクト の荻田氏が公開している行列演算プログラム"mltmats"のソースを同様に最適化オプ ションでコンパイルした実行結果が5.98秒であった。 <プログラムの解説・考察>  Pentium3のキャッシュサイズは結構大きいが、この行列すべてを収めることはでき ないので有効に使う必要がある。そのためには、できるだけ同じメモリ領域からの読 み出しを集中させる必要がある。しかしあまり集中させすぎると、今度は演算処理が 増加し、逆に遅くなってしまう。その微妙なバランスを保つのは難しい。このプログ ラムでは、ループを増やすことによって、行列の 処理を分散化し、同じメモリへのアクセスを集中させている。また、メモリアクセス を減らすために、できるだけ演算の項を長くできるような配置にした。

Portable High-Performance技術

今回の課題は多くの人が楽しかったという感想をもってくれたようだ。そこで,鉄は熱い内に打てということわざがあるように,模範となるこの分野の論文を紹介しておこう。いろいろなCPUにおいて行列の積を高速に計算するCプログラムを自動生成するCプログラムを作成するプロジェクトがある。PhiPackプロジェクトである。このプロジェクトはUCBerkeleyの電気電子情報学科のDemmel教授たちによるものである。そのプロジェクトを解説した論文(pdf)を紹介しよう。これには,いろいろなテクニックが紹介されているので,今読むととても面白いこと請け合いである。(6月2日22:30)


©大石進一

このページのURIはhttp://www.oishi.info.waseda.ac.jp/~oishi/lec2001/p-2.htm

最終更新:2001/6/6 | トップページ