作题时遇到以下几个问题,其中关于浮点类型的存储和转换的问题应该算是比较典型的,在此记录。数组
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 }