在多大程度上,IEEE754浮点数满足LessThanComparable?

5

TL;DR IEEE754浮点数值,包括NaN,是否满足LessThanComparable?

具体而言,问题“为什么Release/Debug对std::min的结果不同?”让我查找了LessThanComparable

该类型必须使用<运算符,并且结果应具有标准语义。

要求

如果给定类型T,则类型T满足LessThanComparable,如果

给定

  • a、b和c是T或const T类型的表达式

以下表达式必须有效并具有其指定的效果

建立严格弱序关系,具有以下属性 (...)

我在标准文档中仔细查看了一遍,似乎基本上也是这样说的,我还查看了严格弱序的维基百科定义。

有些人认为 包括NaN在内的IEEE浮点值集合不符合这个概念:任何一侧与NaN的比较都将始终返回false,我一直在查看定义,对我来说是否存在NaN并不明显是否会破坏严格弱序

对于维基百科给出的列表:

  • 对于集合S中的所有x,不成立x < x(反自反性)。
  • 对于集合S中的所有x、y,如果成立x < y,则不成立y < x(非对称性)。见下文
  • 对于集合S中的所有x、y、z,如果成立x < y且y < z,则成立x < z(传递性)。
  • 对于集合S中的所有x、y、z,如果x与y无法比较(既不成立x < y也不成立y < x),且y与z无法比较,则x与z无法比较(不可比较性的传递性)。

看起来,维基百科上明确定义的严格弱序公理明确指出了可能存在的不可比较值:NaN在这里似乎是一个很好的候选?

另一方面,标准说:(25.5/4)

如果我们将equiv(a, b)定义为!comp(a, b) && !comp(b, a),那么要求comp和equiv都是传递关系:

(4.1) - comp(a, b) && comp(b, c)意味着comp(a, c)

(4.2) - equiv(a, b) && equiv(b, c)意味着equiv(a, c)

有了这些定义,equiv(x, NaN)始终为true(因为!comp(a, NaN)==true 并且 !comp(Nan, a)==true:与NaN的比较产生false,否定则产生true)

但很明显(4.2)不满足,例如:

 equiv(3.0, NaN) && equiv(NaN, 7.0) **does not** imply equiv(3.0, 7.0)

那么标准定义的不是严格弱序,或者更可能的是我在这里漏掉了什么吗?

1
相关:LWG问题1016 - xskxzr
3个回答

8

Strict weak ordering 要求存在强序等价类。IEEE754标准不满足这个要求。

问题不在于存在多个等价的 NaN 值,而是整个 NaN 类与实数轴无序。

违反了(4.2)的规定,导致你从Wikipedia引用的第四个条目中的测试也失败了(让y是一个NaN)。


举个允许在 strict weak ordering 中不可比较的例子,考虑符号-幅度整数。那么:

-4 < -3 < -2 < -1 < { -0, +0 } < +1 < +2 < +3 < +4

既不成立 -0 < +0 也不成立 +0 < -0,因此排序是弱的。但是由这些等价值组成的类与所有其他值都有强序。


另一种表达你的第一句话的方式是说,如果x和y在彼此之间是无序的,那么将y与z进行比较的结果必须与将x与z进行比较的结果相同。 - supercat

2

IEEE754浮点数,包括NaN,不满足LessThanComparable。

如果您从维基百科中取出第四个项目,并将uncomparable替换为equiv,则与std中的条件相同。


这是一个很好的答案,基本上回答了我所有关于C++的疑问:

https://dev59.com/72sz5IYBdhLWcg3wJUUo#8097097

它甚至引用了我在上面问题结尾处引用的std中的同一段落:

如果我们将equiv(a,b)定义为!comp(a,b)&& !comp(b,a),那么要求是comp和equiv都是传递关系...equiv(a,b)&amp; equiv(b,c)意味着equiv(a,c)

对于a = 0.0,b = NaN,c = 1.0,comp = std::less<double>(),这将失败

它还解决了一个有趣的问题:

我一直认为有点奇怪的是标准以键类型而不是以添加到容器中的实际键值来表达要求。我相信,如果实现支持NaN,则您可以选择将其解读为不保证map<double,int>具有定义行为,而不管您是否实际上将NaN添加到实例中。


考虑到这一点,是否有一个标准的或Boost函数对象可以替代std :: less<float>,或者建议的解决方案是自己编写? - Ben

1
您似乎在说维基百科的定义允许NaN,但标准的定义不允许。我认为您是错误的。以下是维基百科的定义:
对于集合S中的所有x、y和z,如果x与y不可比(既不是x < y也不是y < x),并且y与z不可比,则x与z不可比(不可比性的传递性)。
假设x是3.0,y是NaN,z是7.0。x与y不可比,y与z不可比。因此x与z不可比。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接