CCF-CSP 201903-1 小中大(常见浮点错误)
Posted sci-dev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCF-CSP 201903-1 小中大(常见浮点错误)相关的知识,希望对你有一定的参考价值。
做题时遇到如下几个问题:而从第2开始应该算是比较典型而容易出错的,在此记录。
1. %g占位符:
题目要求“对于整数,直接输出整数”。可能会想到直接浮点运算,结果为整数时,小数点后全为0,省略后,看起来像输出了一个整数。于是利用printf的占位符“%g”输出,但这种做法存在严重的问题:当数据较长或较短时%g相当于%e,即采用了科学计数法,而不是简单地省略小数点后多余的0。
虽然%f不存在该问题,但会输出小数点后多余的0。
而接下来分析的机器相关问题将彻底否定这种利用浮点统一计算的想法:
2. 浮点是实数的近似表示:
浮点数在机器内部是由二进制近似表示的(比较常见的是IEEE745),不是准确值,如下为两个实例:
(int)((double)2.3*100) = 229
(int)((float)2.3*100) = 230
这类情况,特别是转换成整数后,在某些程序中会直接造成逻辑/结果错误(如本题)。所以综合之前提到的占位符问题,本解将结果为浮点或整数两种情况分开处理。
同时还需注意:
3. 浮点精度:
float有效数字为7~8位,而double为15~16位。 若超出有效位数,则精度丢失。e.g:
100000000.0f / 211111111.0f = 155555552.0 (ERROR)
理想结果本应为155555555.5 (double)
所以
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
以上是关于CCF-CSP 201903-1 小中大(常见浮点错误)的主要内容,如果未能解决你的问题,请参考以下文章