作題時遇到以下幾個問題,其中關於浮點類型的存儲和轉換的問題應該算是比較典型的,在此記錄。數組
1. 浮點是實數的近似表示:spa
浮點數在機器內部是由二進制近似表示的(比較常見的格式由IEEE745規定),不是準確值,以下爲兩個實例:code
(int)((double)2.3*100) = 229
(int)((float)2.3*100) = 230blog
2. 浮點精度:數學
float有效數字爲7~8位,而double爲15~16位。 若超出有效位數,則會發生精度損失。e.g:
100000000.0f / 211111111.0f = 155555552.0 (ERROR)
理想結果本應爲155555555.5 (double)it
3. %g佔位符:
題目要求「對於整數,直接輸出整數」。當時個人想法是直接浮點運算,當結果爲整數時省略小數點後的0,使其在呈現上如同輸出了一個整數。因而利用printf的佔位符「%g」輸出,但這種作法存在嚴重的問題:當數據較長或較短時%g會自動改用科學計數法,使得結果出錯。 雖然%f不存在該問題,但會輸出小數點後的0,一樣使結果錯誤。io
具體分析以下:class
(1). 首先聲明靜態存儲的數組s用以存儲被輸入的全部測量數據。題目明確測量數據的絕對值小於等於1e7,因此聲明數組元素類型爲int便可保證讀入數據時不發生溢出;題目明確測量數據最多有1e5個,所以數組的元素個數應很多於1e5。循環
(2). 編寫數據輸入程序,首先讀入第一個整數n,表示測量數據的個數。以後利用循環結構分別將全部測量數據讀入以前聲明的數組s中,以供後續程序處理。二進制
(3). 編寫數據處理程序:
1. 首先要找出最小值與最大值,因爲題目明確輸入數據有序,即保證升序或降序,故最值必定位於輸入數據的首位置和尾位置。從首尾元素中選出極小值,做爲整個序列的最小值;同理選出極大值做爲整個序列的最大值。
2. 其次求出中位數。由數學可知存在兩種狀況:如有奇數個數據,則直接選擇中間位置的元素值做爲中位數;如有偶數個數據,則須要將中間兩個元素a,b求均值做爲中位數,即
由於求均值的過程涉及浮點除法,因此mid引入了浮點結果。題目要求整數與浮點數兩種狀況應單獨輸出,因此須要判斷結果是否爲整數。由等式可知,當(a+b) / 2沒有餘數時,說明能夠整除,此時直接採用整數除法並輸出整數結果;當(a+b) / 2有餘數時,說明結果爲分數,此時再使用浮點除法,並在輸出時經過格式控制保留1位小數。
1 #include <cstdio> 2 #include <algorithm> // max()/min() 3 4 using namespace std; 5 6 static int s[100000+2]; 7 8 /* 9 * 1. 佔位符: 10 * %g 在數據較長或較短時會採用%e輸出,即採用科學計數法。 11 * 而 %f則不存在該問題,但輸出小數點後多餘的0。 12 * 2. float精度: 13 * float有效數字爲7~8位,而double爲15~16位。 若超出有效位數,則精度丟失。e.g: 14 * 100000000.0f / 211111111.0f = 155555552.0(ERROR) 15 * 155555555.5 (double) 16 * 3. 浮點向整數轉換的精度丟失問題: 17 * (int)((double)2.3*100) = 229(ERROR) 18 * (int)((float)2.3*100) = 230(?) 19 * 20 * 4. 同3,整數向浮點轉換:浮點存儲的是近似值,可能形成整數數值變化。 (2問題之根源) 21 */ 22 int main(void) { 23 int n; 24 scanf("%d", &n); 25 for(int i=0; i <n; i++) { 26 scanf("%d", &s[i]); 27 } 28 29 int n_max = max(s[0], s[n-1]); 30 int n_min = min(s[0], s[n-1]); 31 32 if (n & 1) { 33 printf("%d %d %d\n", n_max, s[n/2], n_min); 34 } else { 35 if ( (s[n/2-1]+s[n/2]) & 1 ) 36 printf("%d %.1lf %d\n", n_max, (double)(s[n/2-1]+s[n/2])/2.0, n_min); 37 else 38 printf("%d %d %d\n", n_max, (s[n/2-1]+s[n/2])/2, n_min); 39 } 40 41 return 0; 42 }