[英]How to compare two complex numbers?
在C中,復數是浮點數或雙精度數,並且與規范類型具有相同的問題:
#include <stdio.h>
#include <complex.h>
int main(void)
{
double complex a = 0 + I * 0;
double complex b = 1 + I * 1;
for (int i = 0; i < 10; i++) {
a += .1 + I * .1;
}
if (a == b) {
puts("Ok");
}
else {
printf("Fail: %f + i%f != %f + i%f\n", creal(a), cimag(a), creal(b), cimag(b));
}
return 0;
}
結果:
$ clang main.c
$ ./a.out
Fail: 1.000000 + i1.000000 != 1.000000 + i1.000000
我試試這個語法:
a - b < DBL_EPSILON + I * DBL_EPSILON
但編譯器討厭它:
main.c:24:15: error: invalid operands to binary expression ('_Complex double' and '_Complex double')
if (a - b < DBL_EPSILON + I * DBL_EPSILON) {
~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
這最后工作正常,但它有點挑剔:
fabs(creal(a) - creal(b)) < DBL_EPSILON && fabs(cimag(a) - cimag(b)) < DBL_EPSILON
您可以計算其差值的復數絕對值(也稱為范數 , 模數或幅度 ),而不是比較復數分量,即復平面上兩者之間的距離:
if (cabs(a - b) < DBL_EPSILON) {
// complex numbers are close
}
即使沒有精度問題,小的復數也會接近零,這個問題也存在於實數中。
比較2個復數浮點數非常類似於比較2個實數浮點數。
比較精確等價通常是不夠的,因為涉及的數字包含小的計算錯誤。
所以而不是if (a == b)
代碼需要if (nearlyequal(a,b))
通常的方法是double diff = cabs(a - b)
,然后將diff
與一些小的常量值diff
,如DBL_EPSILON
。
當a,b
為大數時a,b
這會失敗 a,b
因為它們的差異可能比DBL_EPSILON
大許多個數量級,即使a,b
僅與它們的最低有效位不同。
對於小數字也是如此,因為a,b
之間的差異可能相對較大,但是比DBL_EPSILON
小許多個數量級,因此當值相對完全不同時返回true
。
復數實際上在問題上增加了另一個維度問題,因為實部和虛部本身可能會有很大不同。 因此, nearlyequal(a,b)
的最佳答案高度依賴於代碼的目標。
為簡單起見,讓我們使用差異的大小與a,b
的平均大小進行比較。 控制常數ULP_N
近似於允許a,b
不同的最小重要性的二進制數字的數量。
#define ULP_N 4
bool nearlyequal(complex double a, complex double b) {
double diff = cabs(a - b);
double mag = (cabs(a) + cabs(b))/2;
return diff <= (mag * DBL_EPSILON * (1ull << ULP_N));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.