C 比较浮点数

C 比较浮点数,c,C,在你认为我在问同一个N%的问题之前,请先阅读并注意 我正在做一个项目,在这个项目中,我有更多的函数返回double,它们中的一些可能是相同的,这在我的项目中是一件好事,如果是真的,那么我需要一个double比较,看看它们是否相等 我知道如果(x==y)进行等式比较不是一件聪明的事情,我们不需要说明原因,但我们可以检查,这是问题的一部分 语言(标准)是否保证比较为100% 如果是,则可以使用以下程序: #include <stdio.h> int main(void){ do

在你认为我在问同一个N%的问题之前,请先阅读并注意

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

我知道如果(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);
    }
}
#包括
内部主(空){
双x=3.14;
双y=3.14;
if(xy){
/*他们不平等*/
}否则{
/*如果相等,将在此处调用foo()\n“*/
foo(x,y);
}
}
foo(x,y);
得到执行了吗?因为
x
y
在这里应该相等

编辑: 这个问题并不寻求一种比较两个double的方法,只是我应该使用,还是不应该使用而不是==

\35; include
#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");
   }
}
内部主(空){ 双x=3.14; 双y=3.14; if(xy){ /*他们不平等*/ }否则{ /*如果相等,将在此处调用foo()\n“*/ printf(“是”); } }
是的

我知道如果(x==y)
进行等式比较不是一件聪明的事情

这根本不是事实。根据具体问题的不同,这可能是正确的做法,也可能是错误的做法

if (x < y || x > y)
与之相反的是

if (x == y)
一个错了,另一个也错了。一个是对的,另一个也是对的。用
符号而不是
==
编写相等条件=不会突然让它变得更聪明



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

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

是的,同样的问题已经被问了很多次了:

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


所以本质上,是的。除非你真的在用双打做任何事情,否则你可以随心所欲地比较平等。如果您只是将它们用作索引或类似的东西,只要您知道正在为它们分配相同的值,就不会有问题。使用布尔标识不会使您脱离浮点数的基本功能。

首先,您的条件设置有点不合适。要检查所需的不相等项

( x < y || y < x)
我所知道的二重相等的最佳实践是检查某个ε内的紧密度

eps = 0.00000000001

if( abs( x - y ) < eps ) {
    printf("EQUAL!");
}
eps=0.00000000001
如果(abs(x-y)
有些是一样的。。。如果是真的,那么我需要一个双重比较,看看它们是否相等

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

除了可能的NaN,它不是由C定义的(但由定义的很好),这两个比较都是相似的,但是不符合圆锥等价性测试

考虑这个
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;b=-0.0
。两者都相等,但它们的反比通常不相同。一个是正无穷大,另一个是负无穷大

问题归结到你需要多大程度的平等?什么是重要的?使用
memcmp(&a,&b,sizeof a)
无疑是一个很强的测试,对于某些系统来说可能太强了,FP编号可能具有相同的非零值,但编码不同。如果这些差异很重要,或者只是上述例外情况,则由OP决定


如果测试2个不同的代码/函数产生相同的结果,请考虑对它们的差异进行评分。类似于以下内容:将

无符号长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;
}
//可移植性不高
#包括
无符号长ULP(双x){
联合{
双d;
无符号长-长循环;
}u;
断言(sizeof(double)=sizeof(unsigned long-long));
u、 d=x;
如果(单位:0x80000000000000){
u、 ull^=0x80000000000000;
返回0x80000000000000-u.ull;
}
返回u.ull+0x80000000000000;
}
无符号长ULP_差异(双x,双y){
无符号长ullx=ULP(x);
无符号长ully=ULP(y);
如果(x>y)返回ullx-ully;
返回ully-ullx;
}

Michi,您已经知道了标准,那么您在标准中发现了什么,使浮点数的状态比较不是单光子的?或者你是如何得出结论的?请注意,相等的比较也是精确的。就是那个修圆工
$ ./a.exe
OK  a:3.140000, b:3.140000
BAD a:103.140000, b:103.140000
eps = 0.00000000001

if( abs( x - y ) < eps ) {
    printf("EQUAL!");
}
if (a==b) {
  double ai = 1.0/a;
  double bi = 1.0/b;
  printf("%d\n", ai == bi);
} else {
  printf("%d\n", 1);
}
// 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;
}