山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他マンデルブロ描画プログラムVersion2.3
概要
任意の領域に対して単精度または倍精度浮動小数点でマンデルブロを描画します。
計算にはFPU、SSE、SSE2、AVX命令を使うことができます。
画面上でマウスにより任意の範囲を拡大したり、中心点を移動することが可能。
色数が多い領域を自動的に連続拡大する機能があります。
主要計算ルーチンにインラインアセンブラを使用しFPU、SSE、SSE2、AVXを使用しています。
同時計算スレッド数を指定できますのでマルチコアやハイパースレッドを有効に活用できます。
ディスクトップサイズにとらわれず大きな画像を作成可能。8192*8192の画像が作成できました。
画像をクリップボードへコピーできる。
BMP形式で保存可能。
Version 2.1からの改良点は以下の通りです。
計算にはFPU、SSE、SSE2、AVX命令を使うことができます。
画面上でマウスにより任意の範囲を拡大したり、中心点を移動することが可能。
色数が多い領域を自動的に連続拡大する機能があります。
主要計算ルーチンにインラインアセンブラを使用しFPU、SSE、SSE2、AVXを使用しています。
同時計算スレッド数を指定できますのでマルチコアやハイパースレッドを有効に活用できます。
ディスクトップサイズにとらわれず大きな画像を作成可能。8192*8192の画像が作成できました。
画像をクリップボードへコピーできる。
BMP形式で保存可能。
Version 2.1からの改良点は以下の通りです。
古いパソコンを使う機会があったのでWindows 95で使用できるようにVisual C++ 97(5.0)でコンパイルできるようにコードを修正しました。MMX Pentium(Windows 95)で実行できました。
SSEで計算するときに色変換時にSSE2のコードが使われていたので、SSEのみで計算できるように修正しました。
SSE2をサポートしていないCeleron(Coppermine-128k)でSSE2命令が含まれる実行ファイルを実行するとエラーが起こらないことがわかりました。エラーは起こりませんが、正常動作はしません。
テスト環境
コンパイラと実行可能なOS及びCPU
Visual C++ 2013 Express 32bit マルチバイト/UNICODE
Windows XP以上 CPUが対応していれば FPU SSE SSE2 AVXを使用可能Visual C++ 2008
Windows 2000以上 CPUが対応していれば FPU SSE SSE2を使用可能Visual C++ 2005
Windows 98以上 OS CPUが対応していればFPU SSEを使用可能Visual C++ 97(5.0)
Windows 95以上 FPUのみ動作確認環境
以下の環境で動作確認をしました。HITACHI FLORA 270 PC-5NH02-YA5LA MMX Pentium 166MHz with Windows 95 Visual C++ 97で作成した32bit実行ファイル
HITACHI FLORA 270GX PC7NW1-GDE27H420Celeron 600MHz with Windows 98 SE Visual C++ 97で作成した32bit実行ファイル
HITACHI FLORA 270GX PC7NW1-GDE27H420Celeron 600MHz with Windows 2000 Visual C++ 2005で作成した32bit実行ファイル
HP ProBook5220m Core i3-M370 with Windows XP 32bit Visual C++ 2013で作成した32bit実行ファイル
自作PC Core i7-3820 with VirtualBox上のWindows Vista 32bit Visual C++ 2013で作成した32bit実行ファイル
自作PC Core i7-3820 with Windows 7 64bit Visual C++ 2013で作成した32bit/64bit実行ファイル
HP ProBook5220m Core i3-M370 with Windows 8.1 64bit Visual C++ 2013で作成した32bit実行ファイル
HP ProBook5220m Core i3-M370 with Windows 10 64bit Visual C++ 2013で作成した32bit実行ファイル
マンデルブロについて
とした場合で
が成り立つ場合の と を求めます。
実数:
虚数:
この式を簡単に解けないため からスタートして近似していきます。
このときの近似回数をその点の色とします。ただし、Zの絶対値 が2を超えた場合、発散して近似できないので打ち切りとし黒とします。また、近似回数の上限値を超えた場合、黒とします。
これらの計算を画面の横方向X座標をaとし縦方向をY座標をbとしてそれぞれの色を求めます。
原始的なプログラム
void draw(HDC hdc,double x0,double y0){
double a_min=-0.7;
double a_max=1.5;
double b_min=-1.5;
double b_max=1.5;
double a_step=(a_max-a_min)/x0;
double b_step=(b_max-b_min)/y0;
int wx,wy;
wx=0;
for(doublea=a_min;a<=a_max;a+=a_step){
wy=0;
for(doubleb=b_min;b<=b_max;b+=b_step){
double x=0;
double y=0;
int c=0;
for(c=0;c<=511;c++){
double x2=x*x;
double y2=y*y;
double zx=x2-y2-a;
double zy=2*x*y-b;
x=zx;
y=zy;
if(x2+y2>=4)
break;
}
if(c==512){
c=0;
SetPixel(hdc,wx,wy,0);
}else{
SetPixel(hdc,wx,wy,color_map512(c));
}
++wy;
}
++wx;
}
}
メニュー
ファイルメニュー
名前をつけて保存
画像をbmp形式でファイルに保存する。終了
本プログラムを終了する。編集メニュー
コピー
クリップボードへ画像をコピーする。表示メニュー
前に戻る
直前の画像を表示する次に進む
直後の画像を表示する窓ズーム
表示画面上で拡大する領域を指定する。移動
表示画面上でどこを中心にするか指定ズームアウト
表示画面を0.5倍にする。オプション
計算方法、画像サイズ等を指定するダイアログボックスを表示します。左上座標・右下座標
計算するフラクタル座標の範囲を指定します。画像サイズ
作成するフラクタル画像のサイズを指定します。色数
計算の反復回数を指定します。スレッド数
同時に起動するスレッド数を指定します。FPU SSE C++ SSE SSE2 AVX
使用する拡張命令を指定します。初期値
フラクタルの計算諸元を以下の値に設定します。初期座標:-1.33333,-1.00000 1.33333,1.00000 画素数:800*600 反復数: 32768回
自動拡大
自動拡大は現在表示されている領域に対して色数が多い領域(16分割)を拡大し画像を保存するようにしました。拡大は、指定した回数分、自動的に行います。
自動拡大された画像を確認すれば、マンデルブロのお気に入りの領域を探すのが楽になります。
自動拡大された画像はカレントフォルダーにimage日時という名前のフォルダーの中のimageフォルダーに保存されます。
自動拡大した場合に作成された画像ファイルをエクスプローラーでサムネイル表示したものを以下に示します。
座標及び色数等と画像のサムネイルを表示するためのindex.htmlファイルが作成されます。
以下に自動拡大で作成される画像の一覧のリンクを示します。
index.html
各CPUでの実行速度
自動拡大の実行速度
初期座標:-1.33333,-1.00000 1.33333,1.00000画素数:800*600
最大画像数: 100回
最大ループ: 32768回
名称 | スレッド | FPU 倍精度 | C++ 倍精度 | SSE 単精度 | SSE2 倍精度 | AVX 単精度 | AVX 倍精度 | Core(TM) i5-10210U CPU @ 1.60GHz(Comet Lake) | 8 | 65.570 | 36.022 | 76.607 | 20.745 | 47.692 | 12.575 | Core(TM) i5-4300U CPU @ 2.90GHz(Haswel ULT) | 4 | 170.268 | 122.720 | 231.613 | 57.400 | 129.674 | 36.203 | Core(TM) i7-6700 CPU @ 3.40GHz(Skylake) | 8 | 71.93 | 48.817 | 100.02 | 21.861 | 53.709 | 15.080 |
---|---|---|---|---|---|---|---|
Celeron G3900(Skylake) 2.8GHz | 2 | 191.876 | 163.942 | 309.073 | 80.622 | ||
Celeron 600MHz(Coppermine) | 1 | 2274.3 | 2080.111 | 5011.356 | |||
Intel(R) Celeron(R) CPU 900 @ 2.20GHz(Penryn) 2.2GHz | 1 | 479.748 | 575.689 | 838.364 | 364.448 | ||
Pentium(R) 4 CPU 3.20GHz | 2 | 401.2970 | 387.2970 | 794.281 | 196.3910 | ||
Celeron(R) CPU G1620 @ 2.70GHz | 2 | 189.293 | 190.451 | 292.904 | 79.895 | ||
Celeron(R) CPU G1840 @ 2.80GHz | 2 | 191.840 | 168.955 | 296.796 | 76.060 | ||
Core(TM) i3-M370 @ 2.40GHz | 4 | 140.0704 | 120.047 | 228.845 | 63.110 | ||
Core(TM) i7 CPU 860 @ 2.80GHz | 8 | 84.307 | 52.680 | 98.395 | 31.711 | ||
Core(TM) i7 CPU 870 @ 2.93GHz | 8 | 52.167 | 60.575 | 89.840 | 24.476 | ||
Core(TM) i7-3820 CPU @ 3.60GHz | 8 | 37.181 | 37.183 | 76.258 | 18.307 | 30.880 | 10.562 |
Core(TM) i7-3770 CPU @ 3.40GHz | 8 | 42.073 | 40.710 | 75.769 | 21.481 | 34.508 | 13.168 |
Atom Z3775 | 4 | 657.435 | 459.341 | 702.252 | 408.438 | ||
AMD A4-5300 3.4GHz | 2 | 253.094 | 169.127 | 345.930 | 91.557 | 232.238 | 76.721 |
Core(TM) i7-4790 4.0GHz(Haswell Refresh) | 8 | 71.967 | 38.985 | 72.821 | 20.654 | 41.028 | 16.053 |
Core(TM) i7-2600(Sandy Bridge) 3.8GHz | 8 | 49.43 | 47.175 | 83.398 | 24.882 | 40.482 | 14.992 |
Core(TM) i5-4440(Haswell) 3.1GHz | 4 | 97.121 | 86.136 | 142.052 | 39.895 | 65.242 | 23.359 |
各CPUでの実行速度
各CPUの計算時間(単位は秒)をシングルスレッドとCPUのコア数、サポートしている最大スレッド数それぞれ計測してみた。各実行速度は、CPUへのスレッド割り付けは固定しているが、スレッドに*がついている場合は、CPUの割り付けは固定していない速度を表している。
Version 2.3での実行速度
名称 | スレッド | FPU 倍精度 | C++ 倍精度 | SSE 単精度 | SSE2 倍精度 | AVX 単精度 | AVX 倍精度 | Core(TM) i5-10210U CPU @ 1.60GHz(Comet Lake) | 1 | 16.200 | 13.776 | 3.593 | 7.061 | 1.984 | 3.749 | Core(TM) i5-10210U CPU @ 1.60GHz(Comet Lake) | 8 | 4.546 | 3.671 | 1.359 | 1.890 | 0.828 | 1.015 | Core(TM) i5-4300U CPU @ 2.90GHz(Haswel ULT) | 1 | 25.110 | 22.062 | 5.407 | 10.563 | 3.062 | 5.969 | Core(TM) i5-4300U CPU @ 2.90GHz(Haswel ULT) | 4 | 12.484 | 9.875 | 2.563 | 4.734 | 1.391 | 2.859 |
---|---|---|---|---|---|---|---|
i7-7700 CPU(Kabylake) 3.60GHz 65W | 1 | 17.130 | 14.207 | 3.849 | 7.243 | 2.051 | 3.934 | i7-7700 CPU(Kabylake) 3.60GHz 65W | 8 | 4.782 | 3.751 | 1.020 | 1.909 | 0.516 | 1.032 |
i7-6700 CPU(Skylake) 3.40GHz 65W | 1 | 18.346 | 15.673 | 4.001 | 7.992 | 2.141 | 4.188 |
i7-6700 CPU(Skylake) 3.40GHz 65W | 8 | 4.985 | 3.895 | 1.094 | 2.032 | 0.563 | 2.126 |
Celeron G3900(Skylake) 2.8GHz | 1 | 23.87 | 20.361 | 5.391 | 10.486 | ||
Celeron G3900(Skylake) 2.8GHz | 2 | 12.407 | 10.673 | 2.703 | 5.797 | ||
MMX Pentium 166MHz(Tillamook) | 1 | 871.88 | 2615.39 | ||||
Pentium 2 450MHz(Deschutes) | 1 | 213.835 | 414.276 | ||||
Celeron 600MHz(Coppermine) | 1 | 163.41 | 591.60 | 49.431 | |||
Celeron 667MHz(Coppermine) | 1 | 157.8 | 571.17 | 未測定 | 未測定 | ||
Celeron 2.0GMHz(Northwood) | 1 | 70.313 | 69.485 | 14.50 | 27.203 | ||
Atom D2701(Cedarview) 2.13GHz 10W | 1 | 110.32 | 56.207 | 22.954 | 83.115 | ||
Atom D2701(Cedarview) 2.13GHz 10W | 4 | 46.706 | 24.001 | 9.642 | 37.189 | ||
Pentium4 641(Cedar Mill) 3.2GHz 86W | *1 | 50.381 | 48.912 | 11.830 | 19.83 | ||
Pentium4 641(Cedar Mill) 3.2GHz 86W | *2 | 26.112 | 25.050 | 7.376 | 14.283 | ||
Celeron 430(Conroe-L) 1.8GHz 35W | 1 | 40.06 | 48.329 | 9.922 | 23.728 | ||
Celeron 925(Penryn) 2.3GHz 35W | 1 | 29.465 | 35.59 | 7.207 | 15.803 | ||
Intel(R) Celeron(R) CPU 900 @ 2.20GHz(Penryn) 2.2GHz | 1 | 31.73 | 37.58 | 7.597 | 16.786 | ||
Core2Duo E7500(Wolfdale) 2.93GHz 65W | *1 | 22.745 | 27.300 | 5.818 | 12.043 | ||
Core2Duo E7500(Wolfdale) 2.93GHz 65W | *2 | 11.434 | 13.697 | 2.964 | 6.069 | ||
i3-370M(Arrandale) 2.4GHz 35W | 1 | 26.125 | 26.094 | 6.250 | 12.578 | ||
i3-370M(Arrandale) 2.4GHz 35W | 4 | 11.625 | 10.984 | 2.750 | 5.500 | ||
Celeron G1620 2.7GHz 55W | *1 | 24.174 | 22.517 | 5.438 | 10.376 | ||
Celeron G1620 2.7GHz 55W | *2 | 12.000 | 11.188 | 2.703 | 5.219 | ||
Celeron G1840 2.8GHz 53W | 1 | 23.798 | 20.860 | 5.094 | 10.109 | ||
Celeron G1840 2.8GHz 53W | 2 | 12.160 | 10.611 | 2.593 | 5.110 | ||
i7-860(Lynnfield) 2.8GHz 95W | 1 | 19.737 | 19.451 | 4.716 | 9.508 | ||
i7-860(Lynnfield) 2.8GHz 95W | 8 | 5.672 | 5.312 | 1.313 | 2.774 | ||
i7-2600(Sandy Bridge) 3.8GHz 95W | 1 | 16.754 | 16.474 | 3.947 | 7.754 | 1.919 | 3.728 |
i7-2600(Sandy Bridge) 3.8GHz 95W | 8 | 4.586 | 4.508 | 1.108 | 2.090 | 0.546 | 1.030 |
i7-3820(Sandy Bridge-E) 4.2GHz 130W | 1 | 15.05 | 14.960 | 3.523 | 6.949 | 1.728 | 3.346 |
i7-3820(Sandy Bridge-E) 4.2GHz 130W | 8 | 3.956 | 3.807 | 0.930 | 1.840 | 0.432 | 0.890 |
i7-4790(Haswell Refresh) 4.0GHz 84W | 1 | 16.739 | 14.664 | 3.650 | 7.129 | 2.262 | 4.368 |
i7-4790(Haswell Refresh) 4.0GHz 84W | 8 | 4.742 | 3.946 | 1.077 | 1.919 | 1.108 | 1.185 |
Core(TM) M-5Y71 1.2GHz 4.5W | 1 | 23.344 | 15.579 | 4.359 | 8.188 | 2.344 | 4.562 |
Core(TM) M-5Y71 1.2GHz 4.5W | 2 | 13.688 | 8.735 | 2.485 | 4.703 | 1.375 | 2.594 |
Core(TM) M-5Y71 1.2GHz 4.5W | 4 | 11.578 | 7.485 | 2.547 | 4.078 | 1.171 | 2.343 |
AMD A4-5300 65W | 1 | 26.286 | 19.203 | 5.569 | 10.826 | 3.026 | 6.068 |
AMD A4-5300 65W | 2 | 16.411 | 10.374 | 3.026 | 5.679 | 2.652 | 5.975 |
Atom Z3775 1.46GHz(Bay Trail-T) | 1 | 77.906 | 32.469 | 10.938 | 33.688 | ||
Atom Z3775 1.46GHz(Bay Trail-T) | 4 | 32.860 | 13.735 | 4.594 | 14.234 | ||
i5-4440 3.1GHz(Haswell) 3.1GHz 84W | 1 | 20.311 | 17.768 | 4.400 | 8.596 | 2.481 | 4.774 |
i5-4440 3.1GHz(Haswell) 3.1GHz 84W | 4 | 8.580 | 7.504 | 1.840 | 3.635 | 1.045 | 2.012 |
i5-4440 3.1GHz(Haswell) 3.1GHz 84W | 8 | 5.647 | 4.961 | 1.263 | 2.387 | 0.702 | 1.342 |
各CPUの概要
CPU | クロック | 開発コード | コア数 | HT | L1 inst | L1 data | L2 | L3 | ラインサイズ | メモリ帯域 |
---|---|---|---|---|---|---|---|---|---|---|
MMX Pentium | 166MHz | Tillamook | 1 | 無効 | 16kB(4way) | 16kB(4way) | 32 | バス66MHz*8=533MB/s | ||
Pentium 2 | 450MHz | Deschutes | 1 | 無効 | 16kB(4way) | 16kB(4way) | 512kB(4way) | 32 | メモリ100MHz*8=800MB/s | |
Celeron | 600MHz | Coppermine | 1 | 無効 | 16kB(4way) | 16kB(4way) | 128kB(4way) | 32 | メモリ100MHz*8=800MB/s | |
Celeron | 667MHz | Coppermine | 1 | 無効 | 16kB(4way) | 16kB(4way) | 128kB(4way) | 32 | メモリ100MHz*8=800MB/s | |
Celeron | 2.0GHz | Northwood | 1 | 無効 | 12kuμops(8way) | 8kB(4way) | 128kB(2way) | 64 | FSB400MHz DDR266デュアル 4.3GB/s | |
Atom D2701 | 2.13GHz | Cedarview | 2 | 有効 | 32kB*2(8way) | 24kB*2(6way) | 512kB*2(8way) | 64 | DDR3-1066 17.1GB/s | |
Pentium4 641 | 3.2GHz | Cedar Mill | 1 | 有効 | 12kuμops(8way) | 16kB(8way) | 2MB(8way) | 64 | DDR2-533 6.4B/s | |
Celeron 430 | 1.8GHz | Conroe-L | 1 | 無効 | 32kB(8way) | 32kB (8way) | 512kB(2way) | 64 | DDR2-800 6.4GB/s | |
Celeron 925 | 2.3GHz | Penryn | 1 | 無効 | 32kB(8way) | 32kB (8way) | 1MB(4way) | 64 | DDR3-1333 10.7GB/s | |
Celeron 900 | 2.2GHz | Penryn | 1 | 無効 | 32kB(8way) | 32kB (8way) | 1MB(4way) | 64 | DDR3-1333 10.7GB/s | |
Core2Duo | 2.93GHz | Wolfdale | 2 | 無効 | 32k*2(8way) | 32k*2(8way) | 3MB(12way) | 64 | FSB1066MHz DDR2-800 12GB/s | |
Core i3-370M | 2.4GHz | Arrandale | 2 | 有効 | 32kB*2(4way) | 32kB*2(8way) | 256kB*2(8way) | 3MB(12way) | 64 | DDR3-1066 17.1GB/s |
Celeron G1620 | 2.7GHz | Ivy Bridge | 2 | 無効 | 32KB*2(8way) | 32KB*2(8way) | 256kB*2(8way) | 2M(8way) | 64 | DDR3-1600 12.8GB/s |
Celeron G1840 | 2.8GHz | Haswell | 2 | 無効 | 32KB*2(8way) | 32KB*2(8way) | 256kB*2(8way) | 2M(8way) | 64 | DDR3-1333 21GB/s |
Core i7-860 | 2.8GHz(3.46GHz) | Lynnfield | 4 | 有効 | 32k*4(8way) | 32k*4(8way) | 256k*4(8way) | 8M(16way) | 64 | DDR3-1333 21GB/s |
Core i7-2600 | 3.4GHz(3.8GHz) | Sandy Bridge | 4 | 有効 | 32k*4(8way) | 32k*4(8way) | 256k*4(8way) | 8M(16way) | 64 | DDR3-1333 21GB/s |
Core i7-3820 | 3.6GHz(4.2GHz) | Sandy Bridge-E | 4 | 有効 | 32KB*4(8way) | 32KB*4(8way) | 256kB*4(8way) | 10M(20way) | 64 | DDR3-1600 51.2GB/s |
Core i7-4790 | 3.6GHz(4.0GHz) | Haswell Refresh | 4 | 有効 | 32KB*4(8way) | 32KB*4(8way) | 256kB*4(8way) | 8M(16way) | 64 | DDR3-1600 25.6GB/s |
AMD A4-5300 | 3.4GHz(3.6GHz) | Trinity | 2 | 無効 | 64kB(2way) | 16kB(4Way)*2 | 1024kB(16Way) | 64 | DDR3-1600 12.8GB/s | |
Core(TM) M-5Y71 | 1.2GHz(2.9GHz) | Broadwell-Y | 2 | 有効 | 32kB*2(8Way) | 32kB*2(8Way) | 256kB*2(8Way) | 4MB(16Way) | 64 | LPDDR3-1600 25.6GB/s |
Atom Z3775 | 1.46GHz | Bay Trail-T | 4 | 無効 | 32kB*4(8Way) | 24kB*4(6Way) | 1MB*2(16Way) | 64 | LPDDR3-1066 8.533GB/s | |
i5-4440 | 3.1GHz (3.3GHz) | Haswell | 4 | 無効 | 32KB*4(8way) | 32KB*4(8way) | 256kB*4(8Way) | 6M(12way) | 64 | DDR3-1600 25.6GB/s |
Celeron G3900 | 2.8GHz | Skylake | 2 | 無効 | 32kB*2(8way) | 32kB*2(8way) | 256kB*2(4way) | 2MB(8way) | 64 | DD4-2133 デュアル34GB/s |
Core(TM) i5-10210U CPU @ 1.60GHz(Comet Lake) | 1.6GHz | Comet Lake | 8 | 有効 | 32kB*4(8way) | 32kB*4(8way) | 256kB*2(4way) | 6MB(12way) | 64 | DD4-2666 デュアル42.6GB/s |
変更経歴
SSE及びAVXの32768色の反復回数を色に割り当てるソースを修正 2017/09/18
A4-5300の実行速度を追加 2016/01/23
i5-10210Uの実行速度を追加 2020/11/01
マンデルブロ描画プログラム 2014/09/27
A4-5300の実行速度を追加 2016/01/23
i5-10210Uの実行速度を追加 2020/11/01
旧バージョン
マンデルブロ描画プログラムVersion2.1 2014/11/25マンデルブロ描画プログラム 2014/09/27
プログラムソースの概要
mandel23.cpp
_tWinMain
GdiplusStartupによりGDI+を初期化します。GetEncoderClsidによりjpeg用のエンコーダーを取得します。
ウィンドウを起動します。
GdiplusShutdownによりGDI+を開放します。
WndProc
ウィンドウプロシージャーです。WM_CREATE
ウィンドウの初期化時に呼び出されます。ステータスバーの作成をします。
画面のバッファであるメモリコンテキストデバイスの作成及び計算の初期値を設定し、初期値に基づくマンデルブローを描画します。
WM_SIZE
ウィンドウの大きさが変更されたとき呼び出されます。ステータスバーの位置を変更します。
WM_MOUSEMOVE
マウスカーソルが移動されたときに呼び出されます。移動中又は窓ズームに応じた処理を行います。
WM_LBUTTONDOWN
マウスの左ボタンが押された時に呼び出されます。移動中又は窓ズームに応じた処理を行います。
WM_LBUTTONUP
マウスの左ボタンが離された時に呼び出されます。移動中又は窓ズームに応じた処理を行います。
WM_COMMAND
IDM_ALLSET
マンデルブロの座標範囲、画像の大きさ、スレッド数、拡張命令を設定するダイアログボックスを呼び出します。IDM_SAVE2
ファイルを選択するコモンダイアログボックスを表示しファイル名を取得します。save_bmpを呼び出し画像をBMP形式で保存します。
IDM_EXIT
プログラムを終了させます。IDM_BACK
前回の座標で表示します。IDM_FORU
過去の表示から1つ現在に向かって表示を進めます。IDM_ZOOM_OUT
ズームアウトします。IDM_WIN_ZOOM
窓ズームを開始します。IDM_WIN_MOVE
表示を移動させます。IDM_AUTO
自動拡大する回数を入力するダイアログボックスを表示し、回数を取得します。日時を取得し画像を保存するフォルダーを作成します。(CreateDirectory API)
画像のサムネイルを表示するindex.htmlファイルをオープンします。 msg_chk関数よりWindowsメッセージをチェックしWM_PATIN及びWM_KEYDOWNでVK_ESCAPEのメッセージを処理します。
ESCキーが押されている場合(VK_ESCAPE)は自動拡大を終了させます。
現在の座標でマンデルブローを描画します。
color_chkメンバ関数により現在表示されている座標を16分割しそれぞれの使用されている色数を取得します。
16分割のうち最大の色数の領域を取得します。
色数が4以上の場合は、画像をそのままbmpへ保存(save_bmp)、画像を縮小してjpegへ保存(SaveBitmap)、画像へのリンクを作成します。
現在の画像の領域ごとの色数等をMANDEL_PARSEクラスに保存し、MANDEL_TREEクラスに登録します。
色数が4未満又は計算に使用している浮動小数点の型から決まる座標の横幅より小さい場合は、分割された領域へ拡大することはできないと判断し、現在の領域の分割する前の領域に戻り、その領域の分割された領域で色数が最大でかつ描画されたことがない領域へ移動します。
色数が4以上の場合は、分割された領域で一番色数が大きい領域の座標を計算し、前述のmsg_chk関数へジャンプします。
WM_DESTORY
メモリデバイスコンテキストを開放し、ウィンドウを終了させます。WM_CLOSE
ウィンドウ終了時に呼び出されます。WM_PAINT
ウィンドウの表示を更新する必要がある場合呼び出されます。マンデルブロの計算結果は各スレッド用のメモリからウィンドウのバッファ部にコピーされウィンドウに表示されます。
再計算の必要がない場合は、メモリデバイスコンテキスト(バッファ)からウィンドウへコピーします。
SetDlgPro
マンデルブロの座標範囲、画像の大きさ、スレッド数、拡張命令を設定します。AutoSetDlgProc
フラクタル自動拡大する回数を取得するダイアログボックスを表示します。mem_free
各スレッドに参照されるマンデルブロのパラメータを保存しているメモリを解放します。save_bmp
bitmapをbmpファイルへ保存するSaveBitmap
bitmapを拡大縮小してエンコーダーで指定されるフォーマットのファイルとして保存します。保存には、GDI+を使用しており、あらかじめエンコーダーを取得しておく必要があります。
GetEncoderClsid
GDI+で使用するエンコーダーの取得します。引数に与える文字列によって、jpeg,png等の種類を指定できます。
msg_chk
時間のかかる処理にメッセージ処理の機会を与えます。メッセージをチェックし、WM_PAINTの場合は、メッセージを実行します。
WM_KEWYDOWNの場合はESCキーであるかチェックし、ESCキーの場合はtrueを返します。
呼び出し側は、trueの場合、自動拡大を中止します。
GetWinRect
ウィンドウのクライアント領域の大きさを返します。CreateStatus
ステータスバーを作成します。status_bar_str
マウスにより画像の領域を選択中にステータスバーに表示する文字列を作成するmandel_draw_current
指定された座標及び画像サイズのマンデルブロを作成します。この関数では指定数のスレッドを作成(mandel_draw_child関数)し、マルチスレッドでマンデルブロの計算をします。 座標の縦方向を指定したスレッド数で分割して同時計算させている。
mandel_draw_child
選択されている拡張命令(FPU,SSE,AVX等)によりマンデルブロを計算する関数を呼び出します。simd.cpp
IsWindowsVersionOrGreater
OSがAVXに対応しているか確認するために指定バージョン以上かどうかを返します。IsWindows7SP1OrGreater
OSがAVXに対応しているか確認するためにWindows 7 Service Pack 1バージョン以上かどうかを返します。mandel_draw_fpu2
FPUは1スレッドあたり、1ピクセルごとに計算する。FPUレジスタは8個あるが、スタック構造なので、直接レジスタの場所を指定できず、例えばスタックトップとスタックトップからn個目といった指定の仕方をする。
オペランドの一方がスタックトップにある必要があるので、都合が悪い時はfxch命令でスタックトップとスタックトップからn個目の値を交換する。
レジスタに値をロードするとスタックにプッシュされる。スタックがあふれるとエラーが発生するので、スタックトップを破棄する必要がある。この場合、計算後に自動的に破棄する命令(fcomp等)を使うか、fincstp、fstp st(0)等を用いる。
Windowsの64bit版ではFPUを使わないことを奨励している。
Intel自身も高速化のしにくいFPUよりSIMDを使用することを奨励している。
mandel_draw_sse・mandel_draw_sse2
SSEは1スレッドあたり、水平方向4ピクセルを単精度で同時に計算、SSE2は水平方向2ピクセルを倍精度で同時に計算する。座標等の初期値はスカラー命令(1個の浮動小数点を扱う命令)でXMMレジスタに取り込みシャッフル命令でXMMレジスタの各要素(8個又は4個)にコピーする。
以降パックド命令(複数のデータを同時に扱う命令)を使い計算をする。
式が4以上になったときのカウント値を各ピクセルごとに抽出する必要がある。この値は各ピクセルごとに異なる。
4以上がどうかをcmpltps,cmpltpdで比較する。4以上の場合対応する要素のビットが全部0になる。未満の場合はビットが1となる。
同時に扱っているピクセルが全部4以上になった場合をチェックするために、movmskps又はmovmskpd命令で各要素の最上位ビットをdxレジスタに転送している。dxレジスタに対してtestを命令を実行すると、ゼロフラグがセットされているときは各要素全部が4以上なので、ループを抜けることができる。
要素のビットをandでマスクし、4以上の場合は整数の0、未満の場合は1となるようにし、カウンタをadd命令で加算する。こうすれば4未満のピクセルはカウントされ、4以上のピクセルはカウントされないので、同時に扱っているピクセルのループ回数が同一にできSSE又はSSE2命令で記述が可能となる。
mandel_draw_avx・mandel_draw_avxd
AVXは1スレッドあたり、水平方向8ピクセルを単精度で同時に計算又はは水平方向4ピクセルを倍精度で同時に計算する。AVXは浮動小数点に限りスカラー値をYMMレジスタの各要素にコピーすることができる。vbroadcastss,vbroadcastsd命令(AVX2では整数でも可能) 以降パックド命令(複数のデータを同時に扱う命令)を使い計算をする。
式が4以上になったときのカウント値を各ピクセルごとに抽出する必要がある。この値は各ピクセルごとに異なる。
4以上がどうかをvpcmpltps,pcmpltpdで比較する。4以上の場合対応する要素のビットが全部0になる。未満の場合はビットが1となる。
同時に扱っているピクセルが全部4以上になった場合をチェックするために、vpest命令を使います。この命令は2つの256bit値のandをとり、その結果に基づきゼロフラグ、キャリーフラグをセットします。ゼロフラグがセットされているときは各要素全部が4以上なので、ループを抜けることができる。
比較結果に基づきvmaskmovps,vmaskmovpd命令により各要素ごとに1をロードするかしないかを制御している。これにより比較結果により1又は0が設定されるので、カウンタをadd命令で加算する。こうすれば4未満のピクセルはカウントされ、4以上のピクセルはカウントされないので、同時に扱っているピクセルのループ回数が同一にできAVX命令で記述が可能となる。
なおAVXには整数を扱う命令が少ないので、浮動小数点でカウントをし、カウント後、vcvtps2dq,vcvtpd2dqで32bit整数に変換する。
AVX命令には整数を扱う命令が少ないので、YMMレジスタの上位下位を別々にSEE命令によりRGBに変換している。AVX2を用いれば高速に処理できるが、該当するCPUを持っていないのでAVXで記述している。
isAVX
CPUがAVX命令をサポートしているかどうかを返します。color_count
色数を返すcolor_chk
画像の領域ごとの色数をカウントするhi_chk
一番色数の多い領域を返すcpu.cpp cpu.h
基本的には、CPUの物理CPU数・ソケット数等を取得(32/64bit)のCPUクラスにスレッドの割り付け関数(cpu.h)を追加しています。ここでは追加部分のみ記載しております。CPU::alloc_cpu
指定したスレッド数に対する論理CPU番号の配列を返します。スレッド数がコア数以下の場合は、それぞれ異なるコアにスレッドを割り当てます。
スレッド数がコア数以上の場合は、異なるコアに優先して割り当てコア数が最大に達したらCPUのセカンドスレッドに割り当てます。
CPU::getWinCpu
指定したコアのスレッド(CPU)にスレッド(プログラム)を割り当てます。パッケージが複数ある場合は、パッケージ間で連続したコア番号があるとみなしで指定します。ソースコードと実行ファイル
実行ファイルとソースファイルのダウンロード(mandel23.zip 213kByte)
ZIPファイルに含まれるファイル
mandel23.cpp mandel23.exe Visual C++ 2013でビルド Windows XP以上で実行可能 mandel23_0097.exe Visual C++ 97(5.0)でビルド Windows 95以上で実行可能 mandel23_2005.exe Visual C++ 2005でビルド WIndows 98以上で実行可能 mandel.ico mandel.rc cpu.cpp cpu.h resource.h simd.cpp undervc2005.h
Copyright (C) 2012 山本ワールド All Rights Reserved.