浮点数引起的错误

一、浮点数精度

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。

posted @ 2023-05-15 23:38  blogzzt  阅读(63)  评论(0编辑  收藏  举报