一、了解定点数和浮点数
计算机中的实数处理一般有两种方法:定点数和浮点数。定点数指的是小数点位置固定的数值,典型的例子是货币的计算,小数点后两位即为分。
浮点数指的是小数点位置可以向左或向右浮动的数值,这里的“浮动”指的是小数点对数值精度的影响。
比如,$1.23 \times 10^4$和$12.3 \times 10^3$都可以用科学计数法表示为1.23e+04,但是前者的小数点的位置在大数的后面,而后者小数点的位置在大数的前面。所以,浮点数的表示范围相对较大,但是精度相对较低。
二、定点数的详解
在计算中,我们通常需要进行浮点数(实数)和定点数(整数)之间的转换。有时候,我们需要把实数乘以一个精度因子,再将其转换成整数,这就是定点数的表示方法。
#include <stdio.h> #define Q 8 // 小数部分的位数 #define QQ (1<%d\n", a, a_fix); printf("b: %.2lf -> %d\n", b, b_fix); printf("a+b: %.4lf\n", fix(a_fix + b_fix)); return 0; }
上述代码实现了将小数部分为8位的实数转化为整数操作,例如将2.25转换为$2.25 \times 2^8=576$。
三、浮点数的详解
在计算机内部,单精度浮点数32位,双精度浮点数64位。由于存储空间的限制,无法完全精确地表示实数。所以,计算机内部的浮点数通常采用科学计数法表示,在IEEE754标准中,单精度浮点数最高位表示符号,接着是指数部分,然后是尾数部分。
#include <stdio.h> int main() { float a = 1.2345; double b = 12.345; printf("a: %.10f\n", a); printf("b: %.15lf\n", b); return 0; }
输出结果为:
a: 1.2344999313 b: 12.345000000000000
从输出结果可以看出,浮点数的精度不如定点数高。
四、小数点的移位问题
在浮点数的运算中,容易出现小数点的移位问题。比如,我们需要将一个浮点数加上一个整数,但是因为小数点位置的不同,可能会出现问题。
#include <stdio.h> int main() { double a = 1.0, b = 100000000000.0; int c = 1; printf("a+b: %.1lf\n", a+b); // 输出:100000000001.0 printf("(a+c)+b: %.1lf\n", (a+c)+b); // 输出:100000000002.0 printf("a+(c+b): %.1lf\n", a+(c+b)); // 输出:100000000001.0 return 0; }
从输出结果可以看出,在浮点数的运算中,加法并不满足结合律。
五、避免浮点数误差
为了避免浮点数运算中出现误差,我们可以采用避免小数点移位的方法,即将小数转换为整数进行运算。
#include <stdio.h> int main() { double a = 1.0, b = 100000000000.0; int a_fix = a * 1000; int b_fix = b; printf("a_fix+b_fix: %.1lf\n", (double)(a_fix+b_fix)/1000); // 输出:100000000001.0 return 0; }
上述代码中,我们将浮点数乘以一个精度因子1000,再将其转换为整数进行计算。最后再将计算结果转换为浮点数。
六、整数溢出问题
在使用定点数时,有可能会出现整数溢出的问题。当定点数的位数不够用时,需要向左移动小数点,此时整数位数就会增加,如果整数位数过大,就会超出计算机所能表示的范围。
#include <stdio.h> #define Q 3 // 小数部分的位数 #define QQ (1<因此,在使用定点数时,要注意定点数的整数和小数部分的位数,以免溢出。