符合标准的方式来定义浮点等价关系 [英] Standard-compliant way to define a floating-point equivalence relationship

查看:116
本文介绍了符合标准的方式来定义浮点等价关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

相反,我实际上希望在C ++中实现一个二元谓词(<100>符合标准的方式),它实际上实现了一个真正的数学的等值关系(即自反,传递和对称),这样两个双打如果它们在所有方面表示完全相同的值,则区分相同的等价类,如 0.0 -0.0 所有 NaN 值都在相同的等价类中。 (尤其是,默认的 == 不是我想要的,因为在 NaN 的情况下是非自反的。 ,并且不区分 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));



$ b $ p
$ b

我相信这可以处理我所知道和前面描述过的角落案例,有没有其他的角落案件,这不处理,我失踪?上面的二元谓词保证用于定义一个根据C ++标准的等价关系,或者是任何未指定的行为,实现定义的等等。



  bool equiv(double x,double y) {
return(x == y&&(x ||(1 / x == 1 / y)))|| (x!= x&& y!= y);

$ / code $

$ b $ p上面使用了IEEE的这一事实:


  • 将非零归为零将产生保留符号的无穷大特殊值。因此 1 / -0。产生 -infinity 。具有相同符号的无穷大特殊值比较相等。

  • NaN不相等。


原来的版本,虽然读大多数人更好。从采访经验来看,并不是每个开发人员都知道特殊的浮点值是如何产生和表现的。



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






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


常常听到IEEE浮点这个术语。这个用法是因为这个主题的原始标准是由IEEE出版的。二进制浮点算法的这个标准是许多主机处理器十多年来一直提供的。但是,它的使用不是由C99强制的。本标准中指定的二进制浮点表示法是由Intel x86处理器系列,Sun SPARC,HP PA-RISC,IBM P OWER PC,HP-是DEC-Alpha和大多数现代处理器(一些DSP处理器支持一个子集,或者为了性价比的原因做了小的修改;而其他的则有更大的差别,例如TMS320C3x使用二进制补码)。这个标准还有一个公开的软件实现。

其他表示仍然支持处理器(IBM 390和惠普是DEC - VAX)有一个现有的客户群在出版之前,这个标准是基于这些文件。由于现有的代码依赖于
(IBM 390和HP-是DEC-Alpha支持其公司各自的旧代表和IEC 60559要求),所以这些代表可能会持续一段时间。 / b>

人们普遍认为,一旦IEC 60559标准被指定,所有必需的功能都将由一致的实现来提供。 C程序对IEC 60559结构的依赖性可能因为这种常见的,不正确的信念(撰写文档的人并不总是熟悉这个标准的人)而不能被记录在文档中。与C标准一样,IEC 60559标准没有完全规定每个结构的行为。它还为某些构造提供了可选的行为,例如引发下溢时,并且具有实现可以或不可以使用的可选构造,例如双重标准。 C99并不总是提供一个在这些可选区域中找出实现行为的方法。例如,没有标准宏描述处理下溢的各种选项。


每位计算机科学家应该知道什么是浮点运算


语言和编译器


$ b 歧义



理想情况下,语言定义应该足够精确地定义语言的语义,以证明关于程序的陈述。虽然这对于语言的整数部分通常是正确的,但是在涉及到浮点时,语言定义通常具有大的灰色区域。也许这是由于许多语言设计者认为没有什么可以证明浮点的事实,因为它包含了舍入错误。如果是这样,前面的部分已经证明了这个推理的谬误。本节讨论语言定义中的一些常见的灰色区域,包括如何处理它们的建议。大多数语言定义中的另一个模棱两可的问题涉及溢出时发生的情况,下溢和其他例外。 IEEE标准精确地规定了异常的行为,所以使用这个标准作为模型的语言可以避免在这一点上的任何歧义。

...另一个灰色区域涉及括号的解释。由于四舍五入的错误,代数的结合法则不一定适用于浮点数字。不管语言标准是否规定必须遵守括号,(x + y)+ z可以有完全不同的答案比x +(y + z),如上所述。

....四舍五入可以是一个问题。 IEEE标准非常精确地定义舍入,它取决于舍入模式的当前值。这有时与类型转换中隐式舍入的定义或语言中的显式舍入函数冲突。

语言标准无法指定浮点运算的结果,因为例如可以在运行时更改舍入模式使用 std :: fesetround 。因此,C和C ++语言别无选择,只能将浮点类型的操作直接映射到硬件指令上,而不像之前那样干扰。因此,这些语言不会复制IEEE / IEC标准,也不会强制要求它。

I'm aware of the usual issues with floating point arithmetic and precision loss, so this is not the usual question about why 0.1 + 0.2 != 0.3 and the like.

Instead, I would actually like to implement a binary predicate in C++ (in a 100% standard compliant way) that actually implements a real mathematical equivalence relationship (i.e. being reflexive, transitive, and symmetric), such that two doubles are in the same equivalence class if they represent the exact same value in all respects, distinguishing corner cases like 0.0 and -0.0 but treating all NaN values as being in the same equivalence class. (In particular, the default == is not what I want because is is non-reflexive in the case of NaN, and does not distinguish between 0.0 and negative -0.0, which I would like to be in different equivalence classes, as they are actually different values and lead to different runtime behaviors).

What's the shortest and simplest way to do this that does not rely on type punning in any way or any implementation-defined behavior? So far I've got:

#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));
}

I believe this handles the corner cases I know about and described earlier, but are there any other corner cases that this doesn't handle that I'm missing? And is the above binary predicate guaranteed to define an equivalence relationship according to the C++ standard, or is any of the behavior unspecified, implementation-defined, etc.?

解决方案

Looks right.

You can actually get rid of function calls for platforms which implement IEEE 754 (Intel's, Power's and ARMs do) because the special floating point values can be determined without calls.

bool equiv(double x, double y) {
    return (x == y && (x || (1 / x == 1 / y))) || (x != x && y != y);
}

The above uses the fact that IEEE:

  • Division of non-zero to zero yields infinity special values that retain the sign. Hence 1 / -0. yields -infinity. Infinity special values with the same sign compare equal.
  • NaNs do not compare equal.

The original version though, reads better for most people. Judging from interviewing experience, not every developer knows how special floating point values arise and behave.

If only NaNs had one representation you could just do memcmp.


With regards to C++ and C language standards, The New C Standard book says:

The term IEEE floating point is often heard. This usage came about because the original standards on this topic were published by the IEEE. This standard for binary floating-point arithmetic is what many host processors have been providing for over a decade. However, its use is not mandated by C99.

The representation for binary floating-point specified in this standard is used by the Intel x86 processor family, Sun SPARC, HP PA-RISC, IBM P OWER PC, HP–was DEC – Alpha, and the majority of modern processors (some DSP processors support a subset, or make small changes, for cost/performance reasons; while others have more substantial differences e.g., TMS320C3x uses two’s complement). There is also a publicly available software implementation of this standard.

Other representations are still supported by processors (IBM 390 and HP–was DEC – VAX) having an existing customer base that predates the publication the documents on which this standard is based. These representations will probably continue to be supported for some time because of the existing code that relies on it (the IBM 390 and HP–was DEC– Alpha support both their companies respective older representations and the IEC 60559 requirements).

There is a common belief that once the IEC 60559 Standard has been specified all of its required functionality will be provided by conforming implementations. It is possible that a C program’s dependencies on IEC 60559 constructs, which can vary between implementations, will not be documented because of this common, incorrect belief (the person writing documentation is not always the person who is familiar with this standard).

Like the C Standard the IEC 60559 Standard does not fully specify the behavior of every construct. It also provides optional behavior for some constructs, such as when underflow is raised, and has optional constructs that an implementation may or may not make use of, such as double standard. C99 does not always provide a method for finding out an implementation’s behavior in these optional areas. For instance, there are no standard macros describing the various options for handling underflow.

What Every Computer Scientist Should Know About Floating-Point Arithmetic says:

Languages and Compilers

Ambiguity

Ideally, a language definition should define the semantics of the language precisely enough to prove statements about programs. While this is usually true for the integer part of a language, language definitions often have a large grey area when it comes to floating-point. Perhaps this is due to the fact that many language designers believe that nothing can be proven about floating-point, since it entails rounding error. If so, the previous sections have demonstrated the fallacy in this reasoning. This section discusses some common grey areas in language definitions, including suggestions about how to deal with them.

... Another ambiguity in most language definitions concerns what happens on overflow, underflow and other exceptions. The IEEE standard precisely specifies the behavior of exceptions, and so languages that use the standard as a model can avoid any ambiguity on this point.

... Another grey area concerns the interpretation of parentheses. Due to round-off errors, the associative laws of algebra do not necessarily hold for floating-point numbers... Whether or not the language standard specifies that parenthesis must be honored, (x+y)+z can have a totally different answer than x+(y+z), as discussed above.

.... rounding can be a problem. The IEEE standard defines rounding very precisely, and it depends on the current value of the rounding modes. This sometimes conflicts with the definition of implicit rounding in type conversions or the explicit round function in languages.

The language standards cannot possibly specify the results of floating point operations because, for example, one can change the rounding mode at run-time using std::fesetround.

So C and C++ languages have no other choice but to map operations on floating point types directly to hardware instructions and not interfere, like they do. Hence, the languages do not copy IEEE/IEC standard and do not mandate it either.

这篇关于符合标准的方式来定义浮点等价关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆