【问题标题】:Why does floor(pow(64,1.0/3)) return 3 but print 4 when the floor() is removed in C++? [duplicate]为什么在 C++ 中删除 floor() 时 floor(pow(64,1.0/3)) 返回 3 但打印 4? [复制]
【发布时间】:2016-12-05 12:59:02
【问题描述】:

我需要找到给定数字 (x) 的第 n 次根。 x 可以大到 1e12n 可以大到 50。floor(pow(64,1.0/3)) 返回 3,请帮我解决这个问题,如果不能请您建议一个替代方案,牢记?
编辑:我知道浮点精度,我想问在这种情况下应该有什么替代方案。
甚至下面的代码也会返回True double x = pow(64,1.0/3); return x==(int)x;

【问题讨论】:

  • 因为 3.999999999 的下限是 3 而不是 4。将结果视为小数而不是整数。
  • 1.0/3 不完全是三分之一。浮点数只是实数的近似值。
  • 这就是我要求替代方案的原因:/
  • “替代方案”是实现浮点值是什么(十进制实数的二进制表示),因此它们是近似值,如前所述。您必须认识到这一点并相应地重新安排您的计算。
  • 底层的resp到底是什么。周边问题?为什么要排除使用round(pow(64,1.0/3)) 来获取最接近结果的整数?

标签: c++ c++11 debugging math


【解决方案1】:

您正在处理旧的浮点不精确性。请参阅What is the numerical stability of std::pow() compared to iterated multiplication?,尤其是Pascal Cuoq's answer,以深入解释为什么std::pow 的结果特别不精确。由于舍入错误,您偶尔会得到小于 4 的结果,因此std::floor 将舍入为 3。

我上面链接的答案是:

pow 的高质量实施将为您的结果提供 1 ULP 的准确性,而最佳实施将“保证”0.5 ULP。

这里的 ULP 指的是 Unit of Least Precision 或最后位置的单元。知道了这个错误,你可以在调用std::floor之前增加std::pow()的结果。执行此操作的一个好方法是使用std::nextafter,它为您提供下一个更大的可表示浮点值(即 1 ULP up)。我认为,如果 Pascal 关于 std::pow() 精度的声明成立,那么在您的特定示例中,调用 nextafter 一次应该会让您回到 4 以上。这是我推荐的代码:

template <typename T>
T floorroot2(T x, T e)
{
  const auto r = std::pow(x, T(1.0)/e);
  return std::floor(std::nextafter(r, r+1));
}

这对我有用 (live example),但如果您想更加确定您是否不信任您的库的 pow 实现,您可能需要添加 2 个 ULP,即调用 nextafter(nextafter(r, r+1), r+1)

【讨论】:

    【解决方案2】:
    #include <iostream>
    #include <cmath>
    using namespace std;
    
    template<class Type>
    Type compute(Type v1, Type v2, Type v3)
    {
        return std::floor(std::pow(v1, v2 / v3));
    }
    
    int main() {
        std::cout << compute<float>(64, 1, 3) << std::endl;
        std::cout << compute<double>(64, 1, 3) << std::endl;
        std::cout << compute<long double>(64, 1, 3) << std::endl;
    }
    

    预期输出:

    4
    3
    4
    

    【讨论】:

      猜你喜欢
      • 2013-02-27
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      • 2010-10-23
      • 1970-01-01
      • 2021-03-16
      • 1970-01-01
      • 2020-02-22
      相关资源
      最近更新 更多