比较浮点数

时间:2016-06-07 17:53:06

标签: c

请您在考虑我之前要求同样的N%问题之前先阅读它,并请注意它。

我正在开发一个项目,我有更多的函数返回double,它们中的一些可能是相同的,这在我的项目中是一件好事,如果是真的那么我需要一个{{ 1}}比较,看看是否相等。

我知道进行平等比较double并不是一件明智的事情,我们也不需要说出原因,但我们可以查看if( x == y )<这个问题的一部分。

语言(标准)是否保证这一点,比较><是100%?

如果是,那么可以使用以下程序:

>

#include <stdio.h> int main(void){ double x = 3.14; double y = 3.14; if( x < y || x > y){ /* Are not Equal */ }else{ /* Are Equal, foo() will be called here\n" */ foo(x, y); } } 会被执行吗?因为此处foo(x, y);X应该相等。

修改 这个问题并没有找到比较两个双重的方法,只是我应该使用的事实,或者我不应该使用&lt; &gt; 而不是 ==

5 个答案:

答案 0 :(得分:3)

  

我知道进行平等比较if( x == y )并不是一件明智的事情

这根本不是真的。根据具体问题,做或做错事可能是正确的。

if (x < y || x > y)

这保证了与 1 完全相同的效果

if (x != y)

相反的效果
if (x == y)

当一个人错了,另一个也错了。当一个是对的,另一个是对的。用<>符号而不是==!=写出相等条件并不会突然变得更聪明。

[1]除非其中一个操作数是NaN。

答案 1 :(得分:1)

如果你想要小数等式,你要么必须使用epsilon比较(即检查数字是否在特定阈值内彼此足够接近),或者非常小心地使用某些定点算法以避免舍入错误

是的,同样的问题被提出的次数超过了必要的次数:

您需要更多地了解比较的工作原理,特别是为什么浮点相等不起作用。这似乎与equals运算符本身无关,正如您所想的那样(对于算术类型[当不涉及NaN等特殊值时],!(x > y || y > x)将始终与x == y相同。事实上,大多数编译器会优化x < y || x > yx != y),而是因为舍入误差首先是浮点运算的基本部分。 x == y确实适用于浮点类型,您可以自由地执行它。在进行任何算术运算之后它会成为一个问题,然后想要比较它们,因为舍入错误会发生什么是不可预测的。

基本上,是的。比较平等你想要的除非你实际上做双打的任何事情。如果您只是将它们用作索引或类似的东西,那么只要您知道要为它们分配相同的值,就不会有问题。使用布尔标识不会使您免于浮点数的基本功能。

答案 2 :(得分:1)

首先,你的条件有点偏。检查你想要的不平等

( x < y || y < x)

不是

(x < y || y > x ) 

只检查两次相同的东西,意思是x&lt; y回来是假的。

忽略这个小问题:

是&gt;和&lt;应该是100%,因为它几乎总是与==相同。唯一的区别是与Nan的不同行为。但它并没有解决你的问题。

这是一个非常人为的例子。

#include <stdio.h>

void foo(double x, double y){
    printf( "OK  a:%f, b:%f\n",x,y);
}

void bar(double x, double y){
    printf( "BAD a:%f, b:%f\n",x,y);
}

int main(void){

    double x = 3.14;
    double y = 3.14;


    if( x < y || y < x){
        /* Are not Equal */
        bar(x, y);
    }else{
        /* Are Equal, foo() will be called here\n" */
        foo(x, y);
    }

    for( int i = 0; i < 1000; i++) {
        y = y + 0.1;
    }

    x = x + 100;

    if( x < y || y < x){
        bar(x, y);
    }else{
        /* Are Equal, foo() will be called here\n" */
        foo(x, y);
    }
}

这是你的输出(暗示它的坏)

$ ./a.exe
OK  a:3.140000, b:3.140000
BAD a:103.140000, b:103.140000

我知道双重平等的最佳实践是检查某些epsilon中的接近程度,

eps = 0.00000000001

if( abs( x - y ) < eps ) {
    printf("EQUAL!");
}

答案 3 :(得分:1)

  

其中一些是相同的......如果是真的那么我需要进行双重比较以确定是否相等。

OP正在质疑测试FP平等的两种不同方法,并想知道它们是否在功能上相似。

除了可能没有被C定义的NaN(但由IEEE 754明确定义),两个比较相似但失败锥形等价测试

考虑这个double代码:

if (a==b) {
  double ai = 1.0/a;
  double bi = 1.0/b;
  printf("%d\n", ai == bi);
} else {
  printf("%d\n", 1);
}

结果总是 "1"吗?以下是一个例外(鼠标结束)

  

考虑a=0.0; b=-0.0。两者都是相同的,但它们的反转通常是不一样的。一个是正​​无穷大,另一个是负无穷大。

问题归结为你需要如何? NaN重要吗?使用memcmp(&a, &b, sizeof a)肯定是一个强大的测试,并且对于选择系统来说可能太强大了FP编号可以具有相同的非零值,但编码不同。如果这些差异很重要,或者只是上面的例外情况,则由OP决定。

如果测试2个不同的代码/函数是否产生相同的binary64结果,请考虑评估其Unit-in-the-Last-Place差异。类似于以下内容:将unsigned long long ULP_diff()与0,1或2进行比较,具体取决于您的容错能力。

// not highly portable
#include <assert.h>
unsigned long long ULP(double x) {
  union {
    double d;
    unsigned long long ull;
  } u;
  assert(sizeof(double) == sizeof(unsigned long long));
  u.d = x;
  if (u.ull & 0x8000000000000000) {
    u.ull ^= 0x8000000000000000;
    return 0x8000000000000000 - u.ull;
  }
  return u.ull + 0x8000000000000000;
}

unsigned long long ULP_diff(double x, double y) {
  unsigned long ullx = ULP(x);
  unsigned long ully = ULP(y);
  if (x > y) return ullx - ully;
  return ully - ullx;
}

答案 4 :(得分:-2)

#include <stdio.h>

int main(void){
double x = 3.14;
double y = 3.14;

if( x < y || x > y){
    /* Are not Equal */
}else{
    /* Are Equal, foo() will be called here\n" */
    printf("yes");
   }
}

打印是