📅  最后修改于: 2023-12-03 15:13:58.456000             🧑  作者: Mango
在 C++ 中,浮点数的精度是有限的,这是由于浮点数的存储方式决定的。因此,在涉及到浮点数计算的场合,我们需要注意精度问题,避免出现误差。
C++ 中标准的浮点数类型有两种:float
和 double
,其中 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$ 表示指数。
由于浮点数的存储方式决定了它的精度是有限的,因此在进行浮点数计算时,可能会出现精度误差。这种误差又分为舍入误差和截断误差两种。
为了解决浮点数精度问题,在 C++ 中一般有两种方法:
固定精度计算是指在计算过程中,采用自定义的精度位数进行处理,以避免精度误差。可以使用一些开源的高精度计算库,例如 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;
}
相对误差控制是指在计算过程中,控制误差相对于结果的比例。一种常见的方法是设置一个阈值 $\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++ 中常见的问题之一。要想避免出现误差,可以采用固定精度计算或相对误差控制两种方法。此外,在实际应用中,还应该选择合适的数据类型、算法,以及注意程序的算法复杂度等问题。