本章实验主要是讨论单精度浮点数的精度问题。float型数据在小数部分只有23位,而其阶码部分的差值却能达到254位,所以当数据阶码差值超过25位之后要谨慎输入! 具体代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFSIZE 256 int main(int argc, char *argv[]) { char prefix[BUFSIZE]; char next[BUFSIZE]; int i; float sum = 0.0; for (i = 1; i < argc; i++) { float x = atof(argv[i]); sum += x; if (i == 1) { sprintf(prefix, "%.4g", x); } else { sprintf(next, " + %.4g", x); strcat(prefix, next); printf("%s = %.4g\n", prefix, sum); } } return 0; }我们试着以1e20、-1e20和3.14为例:
/* 1.zhaoxiaoan@zhaoxiaoan:/mnt/hgfs/CS2$ ./fsum 1e20 -1e20 3.14 1e+20 + -1e+20 = 0 1e+20 + -1e+20 + 3.14 = 3.14 2.zhaoxiaoan@zhaoxiaoan:/mnt/hgfs/CS2$ ./fsum -1e20 3.14 -1e+20 + 3.14 = -1e+20 3.zhaoxiaoan@zhaoxiaoan:/mnt/hgfs/CS2$ ./fsum -1e20 3.14 1e20 -1e+20 + 3.14 = -1e+20 -1e+20 + 3.14 + 1e+20 = 0 */输入以上数值的加减之后,我们发现,由于相加运算的先后顺序不同,值与值之间可能出现舍入情形!如1和3中仅仅只是输入顺序不同结果便两异,我们对其结果进行判断则可以明显地发现第3次输入发生了舍入的错误!所以在浮点数以至于所有数据类型运算中一定要切实保证其精度关系。 以下给出一些溢出或舍入的判断标准: int型: ①负+负=正,溢出;或者负+负(实值)<-2^31(-2147483648); ②正+正=负,溢出;或者正+正(实值)>2^31-1(2147483647); ③负+正,需自己大概计算实值,若在-2^31 <= x < 2^31范围内,无溢出; float型: |E1-E2|>=25(阶码之差),计算时请注意顺序; double型: |E1-E2|>=54(阶码之差),计算时请注意顺序; *从int型数据转换到float型数据,数字不会溢出,但是可能被舍入(Int型有32位,而float型在表示时会自动对齐至阶码部分,小数部分精度只有23位,不足够表示所有int型),两者转换成double型都不会产生问题; *从double型转换成float型,因为float型范围要小,所以可能溢出至-∞或者+∞(无穷即阶码的每个二进制位全为1并且尾数为0;符号位为0,是正无穷,符号位为1是负无穷。);且由于float型精度更小,所以可能被舍入(float有23位尾数,double有52位尾数); *从float型和double型像int型转换,值会向0舍入,即正直取小,负值取大,往整数取值。