看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《goodrain (mr.fu)》之銘言: : ※ 引述《kiyasuto1 (kiy)》之銘言: : : 各位前輩好!!小弟是用BCB作的二值化,寫了個副程式, : : 想用圖的所有像素灰階值相加除以總像素數目來作門檻! : : (門檻=所有像素灰階值相加/總像素數目) : : 程式碼如下 : : void tw(Byte **a) : : { : : int Bsum; : : float Background; : : for(int i = 0; i < ImgWidth; i++) : : { : : for(int j = 0; j < ImgHeight; j++) : : { : : Background=(Bsum+=a[i][j])/((ImgHeight)*(ImgWidth)); : : } : : } 其實 kiyasuto1 這段最後結果,Background 和 goodrain 的 Background 結果是一樣的。 先看一下下面這段程式碼 #include <stdio.h> int main() { int a=1, b=5, c=2, d=0; printf("a=%d, b=%d, c=%d, d=%d\n", a, b, c, d); d = (a+=b)/c; printf("a=%d, b=%d, c=%d, d=%d\n", a, b, c, d); return 0; } 實際上 d=(a+=b) / c ; 它是分解成 a=a+b; d=a/c; 兩個步驟寫成一行而已, 輸出結果會是 a=1, b=5, c=2, d=0 a=6, b=5, c=2, d=3 於是 kiyasuto1 的這行 Background=(Bsum+=a[i][j])/((ImgHeight)*(ImgWidth)); 也就只相等於下面這兩行而已 Bsum+= a[i][j]; Background = Bsum / ((ImgHeight)*(ImgWidth)) ; 整段看下來的話,除了做了沒必要的除法運算外,和 goodrain 的結果其實是一樣的。 意思是,「以最小修改」為目的的話,原原原 po(kiyasuto1) 程式碼只要改這樣即可 for(int i = 0; i < ImgWidth; i++) { for(int j = 0; j < ImgHeight; j++) { Background=(float)(Bsum+=a[i][j])/((ImgHeight)*(ImgWidth)); } } 只是這樣的確效率不太好,因要算平均的話,其實只要在算完總合時再除以點數即可, 所以loop 裡不必放除法,只要做加法動作即可,於是一般就像 goodrain 之作法。 : 這一段改成 : for(int i = 0; i < ImgWidth; i++) : { : for(int j = 0; j < ImgHeight; j++) : { : Bsum+=a[i][j]; : } : } : Background= (float)Bsum /(ImgHeight)*(ImgWidth); 以下恕刪。 Background 可以用 float 或 double 都沒問題, 但 Bsum 不建議用 float , 「至少」用 double,可以試試下面這個程式 #include <stdio.h> int main() { float f=1.23456789E9f; double d=1.23456789E9; unsigned u=123456789; printf("f=%.16e\nd=%.16e\nu=%u\n", f, d, u); f=f+1.0f, d=d+1.0, u=u+1; printf("f=%.16e\nd=%.16e\nu=%u\n", f, d, u); return 0; } 上面加 1 有影響的,只有 d 和 u 而已,這是因浮點數機制問題, 有興趣的話該去 K IEEE754 spec , 及浮點數 + - * / 大概是怎麼做的。 --- 另,我有個嚴重的疑惑,system 若含 FPU ,其實 double 速度都比 float 快, 精度也比 float 高,為何還堅持要用 float ? 是因一些顯卡裡之 FPU 用 float 較快嗎? -- No matter how gifted you are, alone, can not change the world. -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 180.177.78.41
ericinttu:第一行的 "他" 與 "你",可以改用PTT id來表示. 10/06 02:06
已修改, 謝謝意見 *^_^*
ericinttu:Backgroun 少個d 10/06 02:06
ericinttu:很久以前有看到一篇文章說BCB的float都會轉成double去運 10/06 02:08
ericinttu:算. 不知道可不可信就是了. (我個人是因此而不用float) 10/06 02:09
ericinttu:要用double佔全線,還是float佔半線,跟CPU有很大的關連. 10/06 02:13
tropical72:其實 vc "有時" 也會偷換 http://0rz.tw/w9Orf 現在大 10/06 02:13
tropical72:多 compiler 應都有偷換動作..10/06 02:13
ericinttu:我計組忘光光,留給高手回答好了. (退後十大步 XD) 10/06 02:13
akasan:在x86 double/float 都轉80bit 後才運算 所以才會差不多快 10/06 02:13
akasan:在其他硬體架構下就會較為明顯的差距如你所提GPU 10/06 02:14
akasan:以printf 這個例子來看不太對...因為他會先轉成double 才傳10/06 02:15
tropical72:原來如此, 謝謝 akasan 補充。 10/06 02:14
tropical72:那 printf 有引數可顯示 float 嗎? 10/06 02:19
補齊。 另請教 akasan, 在該 code 裡 float f=1.0f; while(1.0f+f!=1.0f) f/=2.0f; 以我系統裡,正常 f 為 1.192092896e-07F (FLT_EPSILON)時跳出 while loop 這樣就算 printf 出來也不該是 DBL_EPSILON , 所以才判斷有偷轉, 應可這麼解讀吧? ※ 編輯: tropical72 來自: 180.177.78.41 (10/06 02:32)
goodrain:沒有錯一模一樣的東西...我後來才發現原原po的邏輯xd 10/06 03:01
akasan:那段程式用double/float 透過 gcc -O2 -m32 出來幾乎一樣 10/06 03:02
akasan:注意一下code 用mmx or FPU 結果會有不一樣 10/06 03:07
tropical72:嗯, 看來和 compiler 特性與參數也有關係,謝謝指教!! 10/06 03:10
LPH66:printf 主要是變長參數的關係 float 會變成 double 10/06 06:23
LPH66:所以 printf 裡面接到的一定是 double 10/06 06:24