首页  >  文章  >  后端开发  >  为什么 C 浮点运算会产生意想不到的结果,我们如何减轻这些精度异常?

为什么 C 浮点运算会产生意想不到的结果,我们如何减轻这些精度异常?

Barbara Streisand
Barbara Streisand原创
2024-11-04 21:38:02744浏览

Why does C   floating-point arithmetic produce unexpected results, and how can we mitigate these precision anomalies?

C 浮点精度异常和分辨率

尽管 C 中的浮点数广泛使用,但它们在精度方面表现出局限性。考虑以下代码片段:

<code class="cpp">double a = 0.3;
std::cout.precision(20);
std::cout << a << std::endl;

此代码输出 0.2999999999999999889,而不是预期的 0.3。出现这种差异的原因是变量 a 并未完全存储为 0.3 双精度浮点数,而是由于浮点值的有限表示而存储为它的近似值。

当出现更令人惊讶的行为时,会出现以下情况: a 被重复添加 50 次:

<code class="cpp">double a, b;
a = 0.3;
b = 0;
for (char i = 1; i <= 50; i++) {
  b = b + a;
};
std::cout.precision(20);
std::cout << b << std::endl;

这段代码令人惊讶地输出 15.000000000000014211 而不是 15.0。这是因为每次加法都会累积近似误差,导致累积误差大于原始精度。

解决精度异常

要获得精确的结果,需要避免将输出精度设置为大于数字类型的可用数字至关重要。这可以使用 std::numeric_limits 类来实现:

<code class="cpp">#include <iostream>
#include <limits>
int main()
{
        double a = 0.3;
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << a << std::endl;
        double b = 0;
        for (char i = 1; i <= 50; i++) {
                  b = b + a;
        };
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << b << std::endl;
}</code>

此代码使用digits10成员函数将精度设置为双精度浮点数的最大可用位数,即15

浮点运算的局限性

虽然提供的解决方案最大限度地减少了精度误差,但重要的是要认识到浮点运算具有固有的局限性。如果一个循环涉及数千次迭代,即使精度设置适当,累积误差也可能变得很大。在这种情况下,替代数据类型,例如定点数或有理数,可能更适合维护精确值。

以上是为什么 C 浮点运算会产生意想不到的结果,我们如何减轻这些精度异常?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn