c++ - 如何提高计算 float 的精度?

标签 c++

我在 Microsoft Visual Studio Community 2019 中用 C++ 编写了一个代码片段,如下所示:

int m = 11;
int p = 3;
float step = 1.0 / (m - 2 * p);

可变步长是0.200003,我想要的是0.2。有什么提高精度的建议吗?

这个问题来自UNIFORM KNOT VECTOR。节点 vector 是 NURBS 中的一个概念。你可以认为它只是一个像这样的数字数组:U[] = {0, 0.2, 0.4, 0.6, 0.8, 1.0};两个相邻数字之间的跨度是一个常数。节点 vector 的大小可以根据条件改变,但范围在[0, 1]。

整个函数是:


typedef float NURBS_FLOAT;
void CreateKnotVector(int m, int p, bool clamped, NURBS_FLOAT* U)
{
    if (clamped)
    {
        for (int i = 0; i <= p; i++)
        {
            U[i] = 0;
        }

        NURBS_FLOAT step = 1.0 / (m - 2 * p);
        for (int i = p+1; i < m-p; i++)
        {
            U[i] = U[i - 1] + step;
        }

        for (int i = m-p; i <= m; i++)
        {
            U[i] = 1;
        }
    }
    else
    {
        U[0] = 0;
        NURBS_FLOAT step = 1.0 / m;
        for (int i = 1; i <= m; i++)
        {
            U[i] = U[i - 1] + step;
        }
    }
}

最佳答案

让我们看看您的代码中发生了什么:

  1. 表达式 1.0/(m - 2 * p) 产生 0.2,最接近的可表示 double 值为 0.200000000000000011102230246251565404236316680908203125。请注意它有多精确 – 精确到 16 位有效的小数位。这是因为,由于 1.0 是一个 double 字面量,分母被提升为 double,整个计算都是 double 的,因此产生一个 double 值。

  2. 将上一步得到的值写入stepfloat类型。因此,该值必须四舍五入到最接近的可表示值,恰好是 0.20000000298023223876953125。

所以你引用的结果 0.200003 不是你应该得到的。相反,它应该更接近 0.200000003。

Is there any suggestion to improve the precision?

是的。将值存储在精度更高的变量中。例如,不要使用 float step,而是使用 double step。在这种情况下,您计算出的值不会再次四舍五入,因此精度会更高。

你能得到准确的 0.2 值用于后续计算吗?不幸的是,对于二进制浮点运算,不行。在二进制中,数字 0.2 是周期分数:

0.210 = 0.0̅0̅1̅1̅2 = 0.001100110011...2

参见 Is floating point math broken?问题及其答案以获取更多详细信息。

如果您真的需要小数计算,您应该使用库解决方案,例如Boost's cpp_dec_float .或者,如果您需要任意精度的计算,您可以使用例如cpp_bin_float来自同一个图书馆。请注意,这两种变体都比使用内置 C++ 二进制浮点类型慢几个数量级。

关于c++ - 如何提高计算 float 的精度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58501421/

相关文章:

c++ - 加速 std::map 和 boost:unordered_map [] 操作

c++ - C++ 解析器源代码中的无法解释的错误

c++ - VisualStudio 2017 是否已经支持 C++17 代码契约?

c++ - 引用的结构不是 'sticking'

c++ - 在 C 或 C++ 中返回结构是否安全?

c++ - 将 __bridge cast 与 static_cast 结合使用的语法是什么?

C++:在 .lib 成功构建后在 VS2010 中创建 .dll 时出现 "unresolved external symbol"

C++ - 使用指向成员函数的函数指针的问题

c++ - 重载 operator= 在模板类中

c++ - 关于 std::unordered_multimap 中键唯一性的保证