📜  c++ 中固定的精度(1)

📅  最后修改于: 2023-12-03 15:13:58.456000             🧑  作者: Mango

C++ 中固定的精度

在 C++ 中,浮点数的精度是有限的,这是由于浮点数的存储方式决定的。因此,在涉及到浮点数计算的场合,我们需要注意精度问题,避免出现误差。

浮点数的存储方式

C++ 中标准的浮点数类型有两种:floatdouble,其中 float 占用 4 个字节,double 占用 8 个字节。这两种类型都采用 IEEE 754 标准规定的存储方式,即把浮点数分为三部分:符号位、指数位和尾数位。

double 类型为例,它的存储方式如下:

| 符号位 | 指数位 | 尾数位 | | --- | --- | --- | | 1 bit | 11 bits | 52 bits |

符号位表示数值的正负,0 表示正数,1 表示负数;指数位和尾数位共同表示数值的大小和精度。

具体来说,指数位采用偏移码表示,即真实指数值等于存储的指数值减去 1023。在这个基础上,尾数位表示浮点数的大小和精度。尾数位采用科学计数法的形式表示,即:

$$M = 1.b_{1} b_{2} \cdots b_{52} \times 2^{E - 1023}$$

其中,$b_{i}$ 表示尾数位上的二进制数值,$E$ 表示指数。

浮点数精度问题

由于浮点数的存储方式决定了它的精度是有限的,因此在进行浮点数计算时,可能会出现精度误差。这种误差又分为舍入误差和截断误差两种。

  • 舍入误差:当浮点数的小数部分无法全部存储时,系统会采用舍入的方式进行处理。这样就会导致最后结果和实际值有一定的差别。
  • 截断误差:当浮点数的精度超过了系统可以表示的范围时,就会发生截断误差。例如,$0.1$ 在二进制下是一个无限循环小数,因此在计算机中无法精确地表示它。
解决浮点数精度问题

为了解决浮点数精度问题,在 C++ 中一般有两种方法:

1. 固定精度计算

固定精度计算是指在计算过程中,采用自定义的精度位数进行处理,以避免精度误差。可以使用一些开源的高精度计算库,例如 GMP。

示例代码:

#include <iostream>
#include <gmpxx.h>

int main() {
    // 使用 GMP 库计算固定精度的浮点数
    mpf_set_default_prec(100);  // 设置精度为 100 位
    mpf_t pi;
    mpf_init(pi);
    mpf_set_str(pi, "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 10);
    mpf_mul(pi, pi, pi);  // 计算圆的面积
    std::cout << "pi^2 = " << mpf_get_str(nullptr, nullptr, 10, 0, pi) << std::endl;
    mpf_clear(pi);
    return 0;
}
2. 相对误差控制

相对误差控制是指在计算过程中,控制误差相对于结果的比例。一种常见的方法是设置一个阈值 $\epsilon$,当计算结果的相对误差小于等于 $\epsilon$ 时,停止计算。

示例代码:

#include <iostream>
#include <cmath>

double pi(int n) {
    double sum = 0;
    for (int i = 0; i < n; ++i) {
        if (i % 2 == 0) {
            sum += 1.0 / (2 * i + 1);
        } else {
            sum -= 1.0 / (2 * i + 1);
        }
    }
    return 4 * sum;
}

int main() {
    double eps = 1e-6;  // 设置相对误差阈值
    double old_res = 0, new_res = 0;
    int i = 0;
    do {
        old_res = new_res;
        new_res = pi(i++);
    } while (std::abs(new_res - old_res) / old_res > eps);
    std::cout << "pi = " << new_res << std::endl;
    return 0;
}
结论

浮点数精度问题是 C++ 中常见的问题之一。要想避免出现误差,可以采用固定精度计算或相对误差控制两种方法。此外,在实际应用中,还应该选择合适的数据类型、算法,以及注意程序的算法复杂度等问题。