圖形介紹 這是一個疊代公式,式中的變數都是複數。
圖1:曼德勃羅集
只要計算的點足夠多,不管把圖案放大多少倍,都能顯示出更加複雜的局部,這些局部既與整體不同,又有某種相似的地方。圖案具有無窮無盡的細節和
自相似性 。如圖2所示形產生過程,其中後一個圖均是前一個圖的某一
局部放大 :
圖2
圖3
如下是產生圖3的出發點。
出發點:
實部 Real 0.2537269133080432 ,
虛部 Imag. 0.000365995381749671135
The width of that screen is 9.45e-17
圖形來源 圖形是由美國數學家曼徳勃羅教授於1975年夏天一個夜晚,在冥思苦想之餘翻看兒子的
拉丁文 字典時想到的,起拉丁文的原意是“產生無規則的碎片”。曼德勃羅教授稱此為"魔鬼的聚合物"。為此,曼德勃羅在1988年獲得了"科學
行為藝術 大獎".
計算編程 曼德勃羅特集是易
並行計算 的一個典型例子。採用分治技術,
並行算法 設計時分為靜態
任務分配 和動態任務分配(可用work-pool or processor farm)。
其中底部的數據(real_min, imag_min) to (real_max, imag_max)表示
複平面 視窗,real_min表示實部
最小值 ,,imag_min表示虛部最小值,real_max表示實部
最大值 ,imag_max表示虛部最大值.
(-0.84950, 0.21000) to (-0.84860, 0.21090) (0.32000, -0.45000) to (0.50000, 0.05000) (0.26304, 0.00233) to (0.26329, 0.00267) (-0.63500, 0.68000) to (-0.62500, 0.69000) (-0.46510, -0.56500) to (-0.46470, -0.56460) (-1.50000, -1.00000) to (0.50000, 1.00000) 2.曼德勃羅特集的計算
顯示曼德勃羅特集是處理
位映射 圖像的一個例子。首先要對圖像進行計算,且計算量很大。
式中zk+1是複數z = a + bi的第k+1次疊代,c是確定該點在
複平面 中位置的複數值。z的初始值為0。
疊代將一直進行下去,直到z的
幅值 (向量長度,這裡為22ba+)大於2或者疊代次數已經達到某種任意的規定的限度。
用zreal表示z的實部,zimag表示z的虛部。則:
zreal = a * a - b * b + creal zimag = 2 * a * b + cimag 3.順序代碼
structure complex { float real; float image; }; int cal_pixel(complex c){ int count, max; complex z; float temp, lengthsq; max = 256; z.real = 0; z.imag = 0; count = 0; do { temp = z.real * z.real - z.imag * z.imag + c.real; z.imag = 2 * z.real * z.imag + c.imag; z.real = temp; lengthsqc = z.real * z.real + z.imag * z.imag;count++; } while ((lengthsq < 4.0) && (count < max)); //直到z的幅值大於2或者疊代次數達到max return count; } 因此,所有給定的曼德勃羅特點必將處在以原點為中心,半徑為2的圓中。
計算和顯示這些點的代碼需要對
坐標系統 進行一定的縮放來與顯示區域的坐標系統相匹配。
假設顯示高度為disp_height,寬度為disp_
width 。而點在顯示區域中的位置為(x, y)。
如果顯示
複數平面 的這個視窗具有最小值(real_min, imag_min)和最大值(real_max, imag_max),則每個點需用以下係數加以縮放。
c.real = real_min + x * (real_max - real_min) / disp_width; c.imag = imag_min + y * (imag_max - imag_min) / disp_height; 設定
scale_real = (real_max - real_min) / disp_width; scale_imag = (imag_max - imag_min) / disp_height; 縮放代碼:
for (x = 0; x < disp_width; x++){ for (y = 0; y < disp_height; y++) { c.real = real_min + ((float) x * scale_real); c.imag = imag_min + ((float) y * scale_imag); color = cal_pixel(c);display(x, y, color); } } 4.並行代碼
4.1. 靜態任務分配
假定顯示區域為640 × 480,在一個進程中要計算10行。即將10 × 640像素變為一組,共48個進程。
偽代碼如下:
主進程Master
for ( i = 0, row = 0; i < 48; i++, row = row + 10){ send (&row, pi) for (i = 0; i < (480 * 640); i++){ recv(&c, &color, PANY); display(c, color); } } 從進程Slave (process i)
recv(&row, Pmaster); for (x = 0; x < disp_width; x++){ for (y = row; y < (row + 10); y++){ c.real = real_min + ((float) x * scale_real); c.imag = imag_min + ((float) y * scale_imag); color = cal_pixel(c); send(&c, &color, Pmaster); } } 改進:
成組 傳送數據.減少通信啟動次數。先將結果保存在數組中,然後以一個訊息將整個數組傳送給主進程。主進程可用一個
通配符 以任意順序接收來自從進程的訊息。
4.2. 動態任務分配—工作池/處理器農莊(work pool / processor farm)
動態
負載平衡 可以用工作池方法實現。在問題中,像素集(更確切應該是坐標集)構成了任務。任務數是固定的,要計算的
像素數 在計算前是已知的。各個處理器從工作池中請求下一個像素子集的坐標。
主進程
count = 0; row = 0; for (k = 0; k< procno; k++){ send(&row, pk, data_tag); count++; row++; } do { recv(&slave, &r, color, PANY, result_tag); count--; }if (row > 0) 從進程
recv(y, Pmaster, ANYTAG, source_tag); //接收Pmaster傳送的第y行的點 while(source_tag == data_tag) { //判斷是否還有訊息需要處理 c.imag = imag_min + ((float) y * scale_imag); for (x = 0; x < disp_width; x++) { c.real = real_min + ((float) x * scale_real); color = cal_pixel(c); } send(&i, &y, color, Pmaster, result_tag); //將所計算的第y行點的color發給Pmaster recv(y, &r, Pmaster, source_tag); //接收下一任務 } //如果退出while循環, 則一定是source_tag = termiate_tag, 表明沒有任務,程式終止