2015-12-11 3 views
3

В 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 
+0

Вам не нужно брать абсолютное значение 'creal (a) - creal (b)'? Точно 'cimag..'? –

+0

Несомненно, единственный способ сравнить два комплексных числа - сравнить их величину, модуль. –

+0

... и сравнение для равенства будет иметь ту же проблему, что и любые другие сравнения с плавающей запятой, см. [Является ли математика с плавающей запятой?] (Http://stackoverflow.com/questions/588004/is-floating-point-math -broken) –

ответ

3

Сравнение двух комплексных чисел с плавающей запятой очень похоже на сравнение двух чисел с плавающей точкой.

Сравнение для точных эквивалентностей часто бывает недостаточным, поскольку участвующие в них числа содержат небольшие ошибки вычислений.

Таким образом, вместо if (a == b) код должен быть if (nearlyequal(a,b))


Обычный подход double diff = cabs(a - b), а затем сравнивая diff до некоторой малой постоянной величины, как DBL_EPSILON.

Это терпит неудачу когда 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)); 
} 
+1

+1 для подробного объяснения. Если вы используете '1u' вместо' 1', чтобы получить еще один бит диапазона для разрешенной разницы, возможно, вы должны использовать '1LL'. – chqrlie

1

Поскольку комплексные числа представляются в виде чисел с плавающей точкой, вы должны иметь дело с their inherent imprecision. Числа с плавающей запятой «достаточно близки», если они находятся в пределах machine epsilon.

Обычный способ - вычесть их, принять абсолютное значение и посмотреть, достаточно ли он достаточно.

#include <complex.h> 
#include <stdbool.h> 
#include <float.h> 

static inline bool ceq(double complex a, double complex b) { 
    return cabs(a-b) < DBL_EPSILON; 
} 
+4

Зачем беспокоиться с тройным оператором? – chqrlie

+0

'(возврат кабины (a-b) djechlin

+0

@chqrlie Привычка, которую я взял с других языков, не имеющих логического типа. Полагаю, здесь это не обязательно. – Schwern

4

Вместо сравнения сложных компонентов чисел, можно вычислить комплексное абсолютное значение (также известное как нормы, модуль или величин) их разности, который является расстоянием между двумя на комплексная плоскость:

if (cabs(a - b) < DBL_EPSILON) { 
    // complex numbers are close 
} 

Малые комплексные числа будут казаться близкой к нулю, даже если нет точного вопрос, отдельный вопрос, который также присутствует для действительных чисел.

+0

В вашем ответе нет модуля. он также не имеет смысла для нецелых чисел, так как это остаток целочисленного деления. Может быть, ложный друг вашего родного языка? – Olaf

+1

@Olaf: C11 7.3.8.1: * Функции кабинетов вычисляют комплексное абсолютное значение (также называемое нормой, модулем или величиной) z *. «модуль» является правильным математическим термином для этого в отношении комплексных чисел. – chqrlie

+1

@chqrlie [Вы технически правы, *** лучший вид правильного ***] (https://www.youtube.com/watch?v=hou0lU8WMgo), но также сбивает с толку, что не так правильно на сайт об обучении. Там уже что-то еще лучше понимается как «модуль». Просто скажите «абсолютное значение». – Schwern

 Смежные вопросы

  • Нет связанных вопросов^_^