具有相同值但不同类型的参数的 std::floor 函数的不同值

Posted

技术标签:

【中文标题】具有相同值但不同类型的参数的 std::floor 函数的不同值【英文标题】:different values of std::floor function for arguments with same value but different types 【发布时间】: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 的同义词。 【参考方案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 位双打?是不是打错字了?

以上是关于具有相同值但不同类型的参数的 std::floor 函数的不同值的主要内容,如果未能解决你的问题,请参考以下文章

带有 ggplots 的 for 循环生成具有相同值但标题不同的图形

如何使用相同的值但使用现有字段之一的不同数据类型来注释 Django Queryset?

字符串文字不允许作为非类型模板参数

如何删除具有相同属性值但在 NSMutableArray 中有一个的所有对象

将 `std::floor()` 和 `std::ceil()` 转换为整数类型是不是总是给出正确的结果?

c ++继承-具有不同参数类型的相同方法名称