浮点数引起的错误
一、浮点数精度
Float 为单精度,内存中占 4 个字节,有效数位是 7 位。
double为 双精度,占 8 个字节,有效数位是 16 位。
二、常见错误
1. 不能存储全部有效数字
#include <iostream> int main() { float f{ 0.123456789f }; std::cout << f << '\n'; return 0; }
打印:0.123457
2. 采用比较运算符时
#include <iostream> int main() { double d1{ 100.0 - 99.99 }; // should equal 0.01 mathematically double d2{ 10.0 - 9.99 }; // should equal 0.01 mathematically if (d1 == d2) std::cout << "d1 == d2" << '\n'; else if (d1 > d2) std::cout << "d1 > d2" << '\n'; else if (d1 < d2) std::cout << "d1 < d2" << '\n'; return 0; }
d1和d2理应一致,但是打印结果为:d1 > d2
如果用Debugger来看,d1 = 0.0100000000000005116 ,d2 = 0.0099999999999997868,这导致了出现了意料之外的结果。
通常来说,用比较运算符是对的,但是当用于比较的两个数非常接近时,可能出现错误。
3. 使用==和!=时
注意!一定不要在比较浮点数时使用==,因为只有当两个数完全一模一样是,才会返回true,否则即使最小的舍入误差都会导致结果为false。
看以下错误出现的例子:
#include <iostream> int main() { double d{ 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 }; // should sum to 1.0 if (d == 1.0) std::cout << "equal\n"; else std::cout << "not equal\n"; return 0; }
打印结果是:not equal
所以,我们可以用下面这个代码来替代==,
#include <cmath> // for std::abs() // epsilon is an absolute value bool approximatelyEqualAbs(double a, double b, double absEpsilon) { // if the distance between a and b is less than absEpsilon, then a and b are "close enough" return std::abs(a - b) <= absEpsilon; }
还有一些更严谨的方法,但是实现复杂度也更高,具体查看该网页拓展部分:https://www.learncpp.com/cpp-tutorial/relational-operators-and-floating-point-comparisons/
4. 整数除法
我们对两个整数做除法操作,我们想要的是一个浮点数,但是得到的确会是一个整数。
#include <iostream> int main() { int x{ 5 }; int y{ 3 }; std::cout << x << " divided by " << y << " is: " << x / y << '\n'; // integer division return 0; }
打印结果为:5 divided by 3 is: 1
我么可以用static_cast函数将其中一个整数转为浮点数,最后得到的结果就是浮点数。或者写成5.0/7.0。