C++ 定义浮点等价关系的标准兼容方法

C++ 定义浮点等价关系的标准兼容方法,c++,floating-point,C++,Floating Point,我知道浮点运算和精度损失的常见问题,所以这不是为什么0.1+0.2!=0.3等 而实际上,我想在C++中实现一个二进制谓词(强100%标准兼容方式< /强>),它实际上实现了一个实的数学(即自反、传递和对称),使得两个双倍在所有的方面都代表相同的值,在相同的等价类中,区分角情况,如0.0和-0.0,但将所有NaN值视为同一等效类。(特别是,默认的==不是我想要的,因为在NaN的情况下,is是非自反的,并且不区分0.0和负值-0.0,我希望它们位于不同的等价类中,因为它们实际上是不同的值,导致不同

我知道浮点运算和精度损失的常见问题,所以这不是为什么
0.1+0.2!=0.3等

而实际上,我想在C++中实现一个二进制谓词(<>强100%标准兼容方式< /强>),它实际上实现了一个实的数学(即自反、传递和对称),使得两个双倍在所有的方面都代表相同的值,在相同的等价类中,区分角情况,如

0.0
-0.0
,但将所有
NaN
值视为同一等效类。(特别是,默认的
==
不是我想要的,因为在
NaN
的情况下,is是非自反的,并且不区分
0.0
和负值
-0.0
,我希望它们位于不同的等价类中,因为它们实际上是不同的值,导致不同的运行时行为)

做这件事的最短和最简单的方法是什么,不以任何方式依赖类型双关或任何实现定义的行为?到目前为止,我已经:

#include <cmath>

bool equiv(double x, double y)
{   
    return (x == y && (x != 0.0 || std::signbit(x) == std::signbit(y))) ||
           (std::isnan(x) && std::isnan(y));
}
#包括
布尔等价(双x,双y)
{   
返回(x==y&(x!=0.0 | | std::signbit(x)==std::signbit(y)))||
(标准:伊斯南(x)和标准:伊斯南(y));
}
我相信这可以处理我之前知道和描述过的角落案例,但是有没有其他我没有处理的角落案例?上面的二进制谓词<强>保证< /强>是否定义了一个等价于C++标准的关系,或者是任何未指定的行为,实现定义等?

看起来正确。 实际上,对于实现IEEE 754的平台(Intel、Power和ARMs),您可以取消函数调用,因为特殊的浮点值可以在无需调用的情况下确定

bool equiv(double x, double y) {
    return (x == y && (x || (1 / x == 1 / y))) || (x != x && y != y);
}
以上使用IEEE:

  • 非零到零的除法产生无穷多个保留符号的特殊值。因此
    1/-0。
    产生
    -无限
    。具有相同符号的无穷多个特殊值比较相等
  • 南不相等
不过,原版对大多数人来说读起来更好。根据访谈经验判断,并非每个开发人员都知道特殊浮点值是如何产生和表现的

如果NaNs只有一个表示,您就可以执行
memcmp


关于C++和C语言标准,书中说:

IEEE浮点这个术语经常被听到。之所以出现这种用法,是因为关于这一主题的原始标准是由IEEE发布的。这个二进制浮点运算的标准是许多主机处理器十多年来一直提供的。但是,C99没有强制要求使用它

英特尔x86处理器系列、Sun SPARC、HP PA-RISC、IBM Power PC、HP–was DEC–Alpha和大多数现代处理器都使用本标准中指定的二进制浮点表示法(出于成本/性能方面的原因,一些DSP处理器支持一个子集或进行小的更改;而另一些处理器则有更大的差异,例如TMS320C3x使用两个的补码)。本标准还有一个公开的软件实现

处理器(IBM 390和HP–was DEC–VAX)仍然支持其他表示法,这些处理器的现有客户群早于本标准所基于的文档的发布。由于依赖的现有代码,这些表示法可能会继续支持一段时间 在it方面(IBM 390和HP–was DEC–Alpha支持其公司各自的旧版本表示和IEC 60559要求)

人们普遍认为,一旦指定了IEC 60559标准,其所有要求的功能都将由符合标准的实现提供。C程序对IEC 60559结构的依赖性(在不同的实现之间可能有所不同)可能不会被记录,因为这是一种常见的、不正确的信念(编写文档的人并不总是熟悉本标准的人)

与C标准一样,IEC 60559标准没有完全指定每个构造的行为。它还为某些构造提供可选行为,例如当出现下溢时,并且具有实现可能使用或可能不使用的可选构造,例如双重标准。C99并不总是提供查找方法实现在这些可选区域中的行为。例如,没有描述处理下溢的各种选项的标准宏

说:

语言和编译器

歧义性

理想情况下,语言定义应该精确地定义语言的语义,以证明有关程序的语句。虽然这通常适用于语言的整数部分,但语言定义在涉及浮点时通常有很大的灰色区域。这可能是因为许多语言设计者认为关于浮点运算,没有什么可以证明的,因为它会带来舍入误差。如果是这样的话,前面几节已经证明了这种推理的谬误。本节讨论了语言定义中的一些常见灰色区域,包括如何处理它们的建议

…大多数语言定义中的另一个歧义与溢出、下溢和其他异常有关。IEEE标准精确地规定了异常的行为,因此使用该标准作为模型的语言可以避免这一点上的歧义

…另一个灰色区域涉及括号的解释。由于四舍五入错误,关联la