比较运算符的数值精度

Numerical precision of comparison operators

简短的问题:比较运算符的行为是否以最大精度定义? 意思是,如果我有两个精确度相同的数字(x 和 y),当我做 x < y 时,我是否应该总是期待相同的答案?

我意识到这似乎是一个愚蠢的问题,但让我详细说明一下。 我正在使用 double 并且我有一组数字,例如:

0:  62536.5477752959
1:  62536.4840613718
2:  62536.4576412381
3:  62522.8487197062
4:  62536.5473896233
5:  62536.5467941254
6:  62527.3508907998
7:  62536.5477752959
8:  62517.5900098039
9:  62536.5477752959

请注意条目 0、7 和 9 具有相同的值。

当我这样做时(像这样):

int low = 0, high = 0;
for(int i = 0; i < N; ++i) {
  if(x[i] < x[low])
    low = i;
  if(x[i] > x[high]) 
    high = i;
 }
 cout << "low: " << low << " high: " << high << endl;

我有时得到:low: 8 high: 0,有时:low: 8 high: 7 我本来期望总是最低的索引值。

有什么想法吗?

[编辑缺少的大括号。]

是的,假设您的浮点类型为 IEEE754。任何两个 doublexy 表示正好 x < yx == yx > y 中的一个成立,除了一些极端情况,例如 +Inf、-Inf 或 NaN。

当您使用十进制表示法表示浮点值时,开始出现混淆;例如没有 double 62536.5477752959(或您列表中与此相关的任何其他人)。

您提供的数字已被调试器/标准输出器截断,它们不是您提供的实际算法中使用的数字。请放心,相同的十进制数 总是 产生相同的 double,这里没有任意选择:IEEE754 要求选择最接近的 double

如需进一步阅读,请参阅 Is floating point math broken?

最后,将int i替换为int i = 0。目前您的程序的行为是 undefined.

可以使用库来避开 behaviour/limitations 内置类型:

Live On Coliru

#include <boost/multiprecision/cpp_dec_float.hpp>
#include <algorithm>
#include <iostream>

int main() {
    using Float = boost::multiprecision::cpp_dec_float_100;
    std::vector<Float> values = {
        Float{ "62536.5477752959" }, Float{ "62536.4840613718" }, Float{ "62536.4576412381" }, Float{ "62522.8487197062" },
        Float{ "62536.5473896233" }, Float{ "62536.5467941254" }, Float{ "62527.3508907998" }, Float{ "62536.5477752959" },
        Float{ "62517.5900098039" }, Float{ "62536.5477752959" },
    };

    auto hilo = std::minmax_element(values.begin(),values.end());

    std::cout << "low: " << *hilo.first << " high: " << *hilo.second << std::endl;

}

版画

low: 62517.6 high: 62536.5

要打印索引:

// indexes:
std::cout << "low: " << (hilo.first-values.begin()) << " high: " << (hilo.second-values.begin()) << std::endl;