宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取

一、了解定点数浮点数

计算机中的实数处理一般有两种方法:定点数和浮点数。定点数指的是小数点位置固定的数值,典型的例子是货币的计算,小数点后两位即为分。

浮点数指的是小数点位置可以向左或向右浮动的数值,这里的“浮动”指的是小数点对数值精度的影响。

比如,$1.23 times 10^4$和$12.3 times 10^3$都可以用科学计数法表示为1.23e+04,但是前者的小数点的位置在大数的后面,而后者小数点的位置在大数的前面。所以,浮点数的表示范围相对较大,但是精度相对较低。

二、定点数的详解

在计算中,我们通常需要进行浮点数(实数)和定点数(整数)之间的转换。有时候,我们需要把实数乘以一个精度因子,再将其转换成整数,这就是定点数的表示方法。

#include <stdio.h>

#define Q        8        // 小数部分的位数
#define QQ        (1<<Q)    // 2^Q
#define QQ2       (1< %dn", a, a_fix);
    printf("b: %.2lf -> %dn", b, b_fix);
    printf("a+b: %.4lfn", 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: %.10fn", a);
    printf("b: %.15lfn", 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: %.1lfn", a+b);          // 输出:100000000001.0
    printf("(a+c)+b: %.1lfn", (a+c)+b);    // 输出:100000000002.0
    printf("a+(c+b): %.1lfn", 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: %.1lfn", (double)(a_fix+b_fix)/1000);    // 输出:100000000001.0
    return 0;
}

上述代码中,我们将浮点数乘以一个精度因子1000,再将其转换为整数进行计算。最后再将计算结果转换为浮点数。

六、整数溢出问题

在使用定点数时,有可能会出现整数溢出的问题。当定点数的位数不够用时,需要向左移动小数点,此时整数位数就会增加,如果整数位数过大,就会超出计算机所能表示的范围。

#include <stdio.h>

#define Q        3        // 小数部分的位数
#define QQ        (1<<Q)    // 2^Q
#define fract(x)  ((int)((x)*QQ+0.5))
#define fix(x)    ((double)(x)/QQ)

int main()
{
    double a = 128.0;
    int a_fix = fract(a);
    printf("a_fix: %dn", a_fix);
    printf("2*a_fix: %dn", 2*a_fix);  // 输出:512,已经溢出
    return 0;
}

因此,在使用定点数时,要注意定点数的整数和小数部分的位数,以免溢出。