【问题标题】:How to print a double value that is just less than another double value?如何打印一个小于另一个双精度值的双精度值?
【发布时间】:2013-02-11 13:31:18
【问题描述】:

实际上,我正在研究 C++ 中的范围表达式。所以我想要的是如果我有任何像

这样的表达
x<1

然后我的

double getMax(...);

应该返回一个在数轴上正好在 1.000(双精度)之前的双精度值。

我试过这样做

double getMax(double& a)
{
    return (a-numeric_limits<double>::min());
}

但我仍然得到与返回语句相同的值。

我认为 C++ 正在将其转换为 cout 语句中最接近的双精度数。

int main()
{
    double a = 32;
    cout<<scientific<<getMax(a)<<endl;
    return 0;
}

输出:

3.200000e+001

【问题讨论】:

  • 下面所说的,getMax 对开放区间没有意义,getSup 应该准确返回 1。

标签: c++ number-formatting


【解决方案1】:

首先,您需要确保实际打印了足够多的数字,以确保显示double 的所有可表示值。你可以这样做(确保你#include &lt;iomanip&gt;为此):

    std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::max_digits10) << getMax(a) << std::endl;

其次,numeric_limits&lt;&gt;::min 不适合这种情况。如果您的起始值为1.0,则可以使用numeric_limits&lt;double&gt;::epsilon,这是与1.0 可表示的最小差异。

但是,在您的代码示例中,起始值为32。 Epsilon 不一定适用于此。在这种情况下计算正确的 epsilon 是很困难的。

但是,如果您可以使用 C++11(*),那么 cmath 标头中有一个函数可以满足您的需要 std::nextafter

#include <iostream>
#include <limits>
#include <iomanip>
#include <cmath>

double getMax(double a)
{
  return std::nextafter(a,std::numeric_limits<double>::lowest());
}

int main()
{
    double a = 32;
    std::cout << std::scientific
              << std::setprecision(std::numeric_limits<double>::max_digits10)
              << getMax(a)
              << std::endl;
    return 0;
}

我也把它放在liveworkspace上。

解释一下:

double nextafter(double from, double to);

返回从 t​​o 方向的下一个可表示值。所以我在调用中指定了std::numeric_limits&lt;double&gt;::lowest(),以确保您获得下一个可表示的值小于参数。

(*)见下方 Tony D 的评论。您可能无需 C++11 就可以访问nextafter()

【讨论】:

  • 注释行不应该只是a - a * ...::epsilon()吗?
  • 哦,好吧,它会向零舍入。如果四舍五入,2 * a * ...::epsilon() 将是正确的值,但如果不是,则大两倍。哎哟哎哟。
  • @JanHudec 10 是我在提交代码之前运行的测试的剩余部分。我已经删除了它。我不知道与a 相乘是否正确。选择正确的因素超出了我的知识范围——我的主要观点是在 C++11 中使用 nextafter。为了正确计算 epsilon,其他人可能会制作答案。
  • 另一件事是我怀疑 ε 对于以前的可表示值不能正常工作。因为在 1 之前,下一个值是 1.ffffffffffffffp-1,即 1-253,但 ε 是 2-52
  • +1 / 值得注意的是,某些系统在提供的 C 库中提供了此功能,因此即使不使用 C++11,您也可以(不可移植地)使用它:例如kernel.org/doc/man-pages/online/pages/man3/nextafter.3.html(标准:C99,POSIX.1-2001)
【解决方案2】:

我认为你的想法是对的。 查看Setting the precision of a double without using stream (ios_base::precision) 不是为了这个问题,而是为了他们给出的使用precision 的例子。您可能想尝试以 53 的精度打印。

我通常看到“接近但不完全”的方式涉及设置差异阈值(通常称为 epsilon)。在这种情况下,您不会使用 getMax 函数,而是使用小于的 epsilon。 (你可以用 epsilon 值和运算符重载来做一个类。我倾向于避免像瘟疫一样的运算符重载。)

基本上,您需要:

bool lessThanEpsilon(double number, double lessThan, double epsilon)
{
    return (lessThan - number >= epsilon);
}

当然,还有其他品种。等于会检查if Math.abs(number - equals) &lt; epsilon

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 2020-05-24
    相关资源
    最近更新 更多