浮点数比较为啥没有相等的函数

Posted

技术标签:

【中文标题】浮点数比较为啥没有相等的函数【英文标题】:floating point number comparison why no equal functions浮点数比较为什么没有相等的函数 【发布时间】:2019-12-10 08:29:28 【问题描述】:

在浮点数的c++标准中,有std::isgreater比较大,std::isless比较少,那为什么没有std::isequal比较相等呢?是否有一种安全准确的方法来检查double 变量是否等于标准定义的DBL_MAX 常量?我们尝试这样做的原因是我们通过服务协议访问数据,它定义了一个双字段,当没有数据可用时它将发送DBL_MAX,所以在我们的客户端代码中,当它是DBL_MAX时,我们需要跳过它,以及我们需要处理的任何其他内容。

【问题讨论】:

因为比较浮点数的相等性并不好,因为它们容易出现舍入错误。我认为this question 会帮助你。 请查看问题右侧的相关问题列表,其中许多会解释为什么浮点相等比较通常是不可能的。 比较本质上不准确的数字是否相等有什么实际用途?特别是DBL_MAX,这是一个荒谬的巨大数字,精度低得荒谬?如果您告诉我们您到底想要做什么,也许我们可以找到更好的解决方案来实现这一目标。 为什么不a==b @fluter 如果你“在某处读到” "operator == 不适用于 float/double" 那么你需要做更多的阅读,因为这不是真的。事实上,这完全是危险的。假设的std::isequal 并不能解决问题。请参阅docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 【参考方案1】:

isgreaterislessisgreaterequalislessequal><>=<= 相比的兴趣在于它们不会引发 FE_INVALID(浮点异常,这些是与 C++ 异常不同的野兽,并且不会映射到 C++ 异常)与 NaN 进行比较时,运算符会这样做。

由于== 不会引发 FP 异常,因此不需要额外的功能。

注意还有islessgreaterisunordered

如果您不考虑 NaN 或不测试浮点异常,则无需担心这些函数。

考虑相等比较== 是如果您想检查值是否相同(忽略与有符号 0 和 NaN 相关的问题)。根据您达到这些值的方式,有时考虑近似相等比较很有用 - 但不建议系统地使用一个,例如这种近似相等可能不具有传递性。

在您的网络协议上下文中,您必须考虑数据是如何序列化的。如果序列化被定义为二进制,您可能可以重建确切的值,因此 == 是您想要的,因此请与 DBL_MAX 进行比较(对于其他值,请检查为有符号 0 和 NaN 指定的内容,并知道有信号和安静的 NaN 由不同的位模式表示,尽管 IEEE 754-2008 现在推荐其中之一)。如果表示为十进制,则必须检查表示是否足够精确,以便 DBL_MAX 值可重构(并注意舍入模式)。

请注意,我会考虑使用 NaN 来表示没有可用数据的情况,而不是使用可能有效的值。

【讨论】:

【参考方案2】:

是否有安全准确的方法来检查双变量是否等于标准定义的DBL_MAX 常量?

当您通过评估某个表达式获得浮点数时,由于有限精度和舍入误差,== 比较在大多数情况下没有意义。但是,如果您首先将浮点变量设置为某个值,那么您可以使用 == 将其与该值进行比较(有一些例外,例如正零和负零)。

例如:

double v = std::numeric_limits<double>::max();
 conditional assignment to v of a non-double-max value 

if (v != std::numeric_limits<double>::max())
    process(v);

std::numeric_limits&lt;double&gt;::max() 完全可以表示为 double(它是 double),因此这种比较应该是安全的,并且永远不会产生 true,除非重新分配了 v

【讨论】:

我很好奇为什么 会有意义,因为两个操作数上可能会累积错误导致错误结果,就像 == 一样。即使是额外的精度(如 80 位寄存器)也可能导致在琐碎的情况下出现灾难性的 也会被破坏并且毫无意义...... @aka.nice std::isless / std::isgreater 服务于不同的目的:他们suppress floating-point exceptions。所有比较的精度问题仍然存在。从这个意义上说,它们都是“破碎的”。 所以你同意正确的答案是不引发异常,而不是因为不准确而没有意义,就像 AProgrammer 解释的那样。 @aka.nice,我同意。但是OP问了两个问题。第一个是关于std::isgreaterstd::isless。第二个是关于如何检测DBL_MAX程序员回答了第一个,我回答了第二个。 好的,我现在更明白你的回答了。但是我们不知道使用的协议,如果是通过的ASCII十进制值,则必须对其进行解码,并且这些计算也需要一些保证...【参考方案3】:

浮点数之间的相等函数没有意义,因为浮点数有四舍五入。

因此,如果您想比较 2 个浮点数是否相等,最好的方法是声明一个显着的 epsilon(error) 进行比较,然后验证第一个数字是否在第二个左右。

为此,您可以验证第一个数字是否大于第二个数字减去 epsilon 并且第一个数字是否小于第二个数字加上 epsilon。 例如。

if ( first > second - epsilon && first < second + epsilon )
          //The numbers are equal
    else
          //The numbers are not equal
    

【讨论】:

测试first = second = DBL_MAX的比较。 是的,他可以比较这两个数字是否等于 DBL_MAX,但这只有在初始化后没有进行任何操作时才有可能。但是正确的表达是first == second == DBL_MAX 虽然近似相等测试有时很有用,但请不要推荐它们作为相等的默认替代品,因为它们缺少重要的相等属性,例如传递性。 是的,当您应用此比较时,传递性属性丢失的逻辑是,但无论如何,传递性属性在数字的舍入过程中已经丢失......只是精度问题。因此传递性属性保持在小于精度或到某个小数位。 Evg 指出,当first = second = DBL_MAX 时,此函数将返回false,即使数字在任何意义上都是相等的。任何大于您选择的 1/epsilon 的 double 都会发生同样的情况 - 您永远不会得到 second - epsilon == second == firstsecond + epsilon == second == first 的相等性,因此 &gt;&lt; 都会产生 false

以上是关于浮点数比较为啥没有相等的函数的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 比较浮点数的相等

如何在perl中比较浮点数而不只是相等

浮点数比较

浮点数比较

C语言对两个浮点数进行比较的方法

php浮点数比较不相等的问题