为什么我在double和c++之间的比较失败



我正在做一个项目,为了完成它,我需要与double、float。。。问题是,当我比较两个double,它们分别是double的最大值和double+1的最大值时,比较失败。。。我做

if (std::max(d_max + 1.1, (d_max)) == d_max)
  std::cout << "bad" << std::endl;

函数max的答案是d_max,并且显示"坏"。。。有人有想法或解决方案可以通过我的比较获得良好的精度吗?我在谷歌上查了一下,但我发现了更多的解释,而不是我问题的真正解决方案。。。非常感谢!

C++中的所有对象都有一个类型。d_max的类型为doubled_max + 1.1的类型仍然是双重的。如果d_maxdouble的最大值,那么d_max + 1.1是不可表示的,并且将使用最接近的可表示值,即d_max(但是,如果添加一个明显更大的值,则最接近的可以表示值被认为是正无穷大(。所以你的std::max调用相当于:

std::max(d_max, d_max)

演示:

double d_max = std::numeric_limits<double>::max();
bool b = (d_max == (d_max + 1.1));
std::cout << std::boolalpha << b << std::endl;

这给出true作为输出。


作为对你评论的回应,我认为你正在做这样的事情:

double d_max = std::numeric_limits<double>::max();
long double ld = d_max + 1;
std::cout << (d_max == ld) << std::endl;

奇怪的是,你发现d_maxld是相等的。为什么?d_max井为double井。当您执行d_max + 1时,运算的结果也是double——尽管如上所述,d_max + 1的值不能在double中表示,因此选择了最接近的可表示值(d_max(。然后将该值分配给ld

请注意,这不太可能通过确保运算符产生long double(可能是d_max + 1.0L(来解决。在如此巨大的数字下(用IEEE 754表示的10^308附近(,加1不会移动到long double中的下一个可表示值。在我的实现中,我必须添加10289(即1后面跟着289个零(才能实际引起值的变化:

double d_max = std::numeric_limits<double>::max();
long double ld = d_max + 1E289L;
std::cout << (d_max == ld) << std::endl;

此外,不能保证long double具有比double更高的精度。唯一的保证是它的精度不会低于。

让我们假设双精度表示为十进制浮点数,科学表示法。那么,d_max将类似于

9.999999999999999999 ⋅ 10⁹⁹

现在让我们将1.1添加到其中:

9.999999999999999999 ⋅ 10⁹⁹ + 1.1
= 999999999999999999900000000...000 + 1.1
= 999999999999999999900000000...001.1

将其四舍五入到20,甚至40个有效数字(你必须这样做,因为这些类型,即使是长双,也只有有限的信息容量(,你得到。。。?好吧,又是d_max


请注意,减法也是如此,因此

int main() {
  long double d_max = std::numeric_limits<double>::max();
  if(d_max == d_max - 1.1)
    std::cout << "   d_max       = " << d_max
            << "n== d_max - 1.1 = " << d_max + 1.1 << std::endl;
  return 0;
}

输出

   d_max       = 1.79769e+308
== d_max - 1.1 = 1.79769e+308

也就是说,这实际上与d_max是可用的最大值无关,而是它比您添加的值大得多。

最新更新