【问题标题】:different values of std::floor function for arguments with same value but different types具有相同值但不同类型的参数的 std::floor 函数的不同值
【发布时间】:2011-08-11 19:22:49
【问题描述】:

考虑以下几点:

#include <iostream>
#include <cmath>
int main()
{
  using std::cout;
  using std::endl;

  const long double be2 = std::log(2);
  cout << std::log(8.0) / be2 << ", " << std::floor(std::log(8.0) / be2)
      << endl;

  cout << std::log(8.0L) / be2 << ", " << std::floor(std::log(8.0L) / be2)
      << endl;
}

输出

  3, 2
  3, 3

为什么输出不同?我在这里错过了什么?

这里也是键盘的链接:http://codepad.org/baLtYrmy

我在 linux 上使用 gcc 4.5,如果这很重要的话。

【问题讨论】:

  • 仅供参考,Visual C++ 2010 给出:3、3 和 3、3。顺便说一句,我需要执行“std::log(2.0)”而不是“std::log(2)”来避免歧义。
  • @Branko : VC++ 将long double 视为double 的同义词。

标签: c++ logging floor


【解决方案1】:

当我添加这个时:

cout.precision(40);

我得到这个输出:

2.999999999999999839754918906642444653698, 2
3.00000000000000010039712117215771058909, 3

您正在打印两个非常接近但不完全等于 3.0 的值。 std::floor 的本质是,对于非常接近的值,它的结果可能会有所不同(从数学上讲,它是一个不连续的函数)。

【讨论】:

    【解决方案2】:
    #include <iostream>
    #include <cmath>
    #include <iomanip>
    
    int main()
    {
      using std::cout;
      using std::endl;
    
      const long double be2 = std::log(2);
    
      cout << setprecision (50)<<std::log(8.0)<<"\n";
      cout << setprecision (50)<<std::log(8.0L)<<"\n";
      cout << setprecision (50)<<std::log(8.0) / be2 << ", " << std::floor(std::log(8.0) / be2)
           << endl;
      cout << setprecision (50)<< std::log(8.0L) / be2 << ", " << std::floor(std::log(8.0L) / be2)
           << endl;
    
      return 0;
    }
    

    输出是:

    2.0794415416798357476579894864698871970176696777344
    2.0794415416798359282860714225549259026593063026667
    2.9999999999999998397549189066424446536984760314226, 2
    3.0000000000000001003971211721577105890901293605566, 3
    

    如果您检查输出 here,您会注意到两个输出的精度略有不同。这些舍入错误通常会在执行floor() 时在此处对 float 和 double 进行操作,并且出现的结果并不是人们认为应该的那样。

    在处理浮点数或双精度数时,记住两个属性 PrecisionRounding 很重要。

    您可能想在我的回答 here 中了解更多相关信息,同样的推理也适用于此。

    【讨论】:

    • 我看不出输出有什么不同
    【解决方案3】:

    扩展 Als 所说的内容-

    在第一种情况下,您将 8 字节双精度值除以 16 字节长双精度值。在第二种情况下,您将 16 字节长双精度除以 16 字节长双精度。这会导致一个非常小的舍入误差,可以在此处看到:

    cout << std::setprecision(20) << (std::log(8.0) / be2) << std::endl;
    cout << std::setprecision(20) << (std::log(8.0L) / be2) << std::endl;
    

    产生:

    2.9999999999999998398
    3.0000000000000001004
    

    编辑说:在这种情况下, sizeof 是你的朋友(查看精度差异):

    sizeof(std::log(8.0));  // 8
    sizeof(std::log(8.0L)); // 16
    sizeof(be2);            // 16
    

    【讨论】:

    • 8 位双打?是不是打错字了?
    猜你喜欢
    • 2019-12-18
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多