C'de karmaşık sayılarla nasıl çalışılır?


122

C'de karmaşık sayılarla nasıl çalışabilirim? Bir complex.hbaşlık dosyası olduğunu görüyorum , ancak bana bunun nasıl kullanılacağı konusunda fazla bilgi vermiyor. Gerçek ve hayali parçalara verimli bir şekilde nasıl erişilir? Modül ve aşama elde etmek için yerel işlevler var mı?


16
Python koduma bağlanmak daha kolay olduğu için C ++ yerine C kullanıyorum.
Charles Brunet

Yanıtlar:


186

Bu kod size yardımcı olacaktır ve oldukça açıklayıcıdır:

#include <stdio.h>      /* Standard Library of Input and Output */
#include <complex.h>    /* Standard Library of Complex Numbers */

int main() {

    double complex z1 = 1.0 + 3.0 * I;
    double complex z2 = 1.0 - 4.0 * I;

    printf("Working with complex numbers:\n\v");

    printf("Starting values: Z1 = %.2f + %.2fi\tZ2 = %.2f %+.2fi\n", creal(z1), cimag(z1), creal(z2), cimag(z2));

    double complex sum = z1 + z2;
    printf("The sum: Z1 + Z2 = %.2f %+.2fi\n", creal(sum), cimag(sum));

    double complex difference = z1 - z2;
    printf("The difference: Z1 - Z2 = %.2f %+.2fi\n", creal(difference), cimag(difference));

    double complex product = z1 * z2;
    printf("The product: Z1 x Z2 = %.2f %+.2fi\n", creal(product), cimag(product));

    double complex quotient = z1 / z2;
    printf("The quotient: Z1 / Z2 = %.2f %+.2fi\n", creal(quotient), cimag(quotient));

    double complex conjugate = conj(z1);
    printf("The conjugate of Z1 = %.2f %+.2fi\n", creal(conjugate), cimag(conjugate));

    return 0;
}

  ile:

creal(z1): gerçek kısmı al (float crealf(z1)için, uzun duble için creall(z1))

cimag(z1): hayali kısmı elde edin (float cimagf(z1)için, uzun duble için cimagl(z1))

Karmaşık sayılar ile çalışan fonksiyonlar gibi o zaman diğer önemli nokta hatırlamak cos(), exp()ve sqrt()örneğin karmaşık formlar ile değiştirilmesi gerekir ccos(), cexp(), csqrt().


12
Bu double complexnedir? Bu bir dil uzantısı mı yoksa biraz makro sihir mi?
Calmarius

@Calmarius complexstandart bir c99 türüdür (GCC'de başlık altında, aslında _Complex türünün bir takma adıdır).
Snaipe

9
@Snaipe: complexbir tür değil. _ComplexBir tür belirleyici olan , ancak kendi başına bir tür olmayan, genişleyen bir makrodur . Karmaşık türleri float _Complex, double _Complexve long double _Complex.
Keith Thompson

3
Bu yalnızca GCC değil, standartta _Complex'in bir tür belirticisi olduğu ve complex.h'nin _Complex'e genişleyen karmaşık bir makroya sahip olduğu tanımlanmıştır. Aynı şey _Bool ve stdbool.h için de geçerli.
jv110

40

Karmaşık türler, C99 standardından beri C dilindedir ( -std=c99GCC seçeneği). Bazı derleyiciler daha önceki modlarda bile karmaşık türleri uygulayabilir, ancak bu standart olmayan ve taşınabilir olmayan uzantıdır (örneğin, IBM XL, GCC, intel, ...).

Http://en.wikipedia.org/wiki/Complex.h adresinden başlayabilirsiniz - bu, complex.h dosyasındaki işlevlerin açıklamasını verir.

Bu kılavuz http://pubs.opengroup.org/onlinepubs/009604499/basedefs/complex.h.html ayrıca makrolar hakkında bazı bilgiler verir.

Karmaşık bir değişkeni bildirmek için kullanın

  double _Complex  a;        // use c* functions without suffix

veya

  float _Complex   b;        // use c*f functions - with f suffix
  long double _Complex c;    // use c*l functions - with l suffix

Karmaşık bir değer vermek için, aşağıdaki _Complex_Imakroyu kullanın complex.h:

  float _Complex d = 2.0f + 2.0f*_Complex_I;

(aslında burada (0,-0i)kompleksin tek yarısında sayılar ve NaN'lerle ilgili bazı problemler olabilir )

Modül, cabs(a)/ cabsl(c)/ cabsf(b); Gerçek kısmı creal(a), Hayali olan cimag(a). carg(a)karmaşık argüman içindir.

Gerçek bir görsel parçasına doğrudan erişmek (okumak / yazmak) için bu taşınabilir olmayan GCC uzantısını kullanabilirsiniz :

 __real__ a = 1.4;
 __imag__ a = 2.0;
 float b = __real__ a;

1
hemen hemen her karmaşık işlev, derleyici tarafından yerleşik işlev olarak verimli bir şekilde uygulanacaktır. Sadece modern derleyiciyi kullanın ve ona sıfır olmayan bir düzeyde optimizasyon verin.
osgx

3
Bilginize, OP Python bağlamalarından bahsettiğinden, Python ile çalışırken C89'a sadık kalmaya çalışıyorum (Python'un kodunun geri kalanı C89 olduğundan ve uzantınızın Windows üzerinde çalışmasını istiyorsanız, genellikle MVSC ile derlenir ve C89). Yine de kesinlikle gerekli olduğunu bilmiyorum.
detly

1
İfade (complex float) { r, i }, sayının ayrı kısımlarını ayarlamak için ve bağımsız olarak da kullanılabilir (örneğin, sanal kısım NAN iken gerçek kısmın INF olmasına izin verir). Bu, GCC'ye özgü anahtar kelimeyi önler, ancak aslında taşınabilir olup olmadığından emin değilim.
2014

2
Karmaşık desteğin C99'da isteğe bağlı olduğunu unutmayın: derleyiciler tanımlılarsa buna sahip olmayabilirler __STDC_NO_COMPLEX__. Ancak pratikte, büyük derleyicilerde uygulanmaktadır.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Jasen, N1256 taslağının 182. sayfasını kontrol edin open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=182 "7.3 Karmaşık aritmetik < complex.h >". Böyle bir anahtar kelime muhtemelen C99'da kompleksi elle uygulayan mevcut c (C90) programlarını bozmamak için seçilmiştir. <Complex.h> dahil edilmişse, complexmakro olarak tanımlanacak ve genişletilecektir _Complex. Derek M. Jones'un "Yeni C Standardı: Ekonomik ve Kültürel Bir Yorum" (2008) sayfa 500 "karmaşık türler" ile de ilgilenebilirsiniz people.ece.cornell.edu/land/courses/ece4760/…
osgx

9

Complex.h

#include <stdio.h>      /* Standard Library of Input and Output */
#include <complex.h>    /* Standart Library of Complex Numbers */

int main() 
{
    double complex z1 = 1.0 + 3.0 * I;
    double complex z2 = 1.0 - 4.0 * I;

    printf("Working with complex numbers:\n\v");

    printf("Starting values: Z1 = %.2f + %.2fi\tZ2 = %.2f %+.2fi\n", 
           creal(z1), 
           cimag(z1), 
           creal(z2), 
           cimag(z2));

    double complex sum = z1 + z2;
    printf("The sum: Z1 + Z2 = %.2f %+.2fi\n", creal(sum), cimag(sum));
}

4

Kolaylık sağlamak tgmath.hiçin, makro üreten tür için kitaplık dahil edilebilir . Tüm değişken türleri için çift sürümle aynı işlev adını oluşturur. Örneğin, Örneğin, bir tanımlar sqrt()genişler makro sqrtf(), sqrt()veya sqrtl()verilen bağımsız değişkenin türüne bağlı olarak, fonksiyon.

Dolayısıyla, farklı değişken türleri için karşılık gelen işlev adını hatırlamaya gerek yoktur!

#include <stdio.h>
#include <tgmath.h>//for the type generate macros. 
#include <complex.h>//for easier declare complex variables and complex unit I

int main(void)
{
    double complex z1=1./4.*M_PI+1./4.*M_PI*I;//M_PI is just pi=3.1415...
    double complex z2, z3, z4, z5; 

    z2=exp(z1);
    z3=sin(z1);
    z4=sqrt(z1);
    z5=log(z1);

    printf("exp(z1)=%lf + %lf I\n", creal(z2),cimag(z2));
    printf("sin(z1)=%lf + %lf I\n", creal(z3),cimag(z3));
    printf("sqrt(z1)=%lf + %lf I\n", creal(z4),cimag(z4));
    printf("log(z1)=%lf + %lf I\n", creal(z5),cimag(z5));

    return 0;
}

2

Karmaşık sayılar kavramı, negatif ikinci dereceden kökleri hesaplama ihtiyacından matematikte tanıtıldı. Karmaşık sayı kavramı, çeşitli mühendislik alanları tarafından alınmıştır.

Günümüzde bu karmaşık sayılar, fizik, elektronik, mekanik, astronomi vb. Gibi ileri mühendislik alanlarında yaygın olarak kullanılmaktadır.

Negatif bir karekök örneğinin gerçek ve sanal kısmı:

#include <stdio.h>   
#include <complex.h>

int main() 
{
    int negNum;

    printf("Calculate negative square roots:\n"
           "Enter negative number:");

    scanf("%d", &negNum);

    double complex negSqrt = csqrt(negNum);

    double pReal = creal(negSqrt);
    double pImag = cimag(negSqrt);

    printf("\nReal part %f, imaginary part %f"
           ", for negative square root.(%d)",
           pReal, pImag, negNum);

    return 0;
}

-1

Karmaşık değerli bir ifadenin gerçek kısmını çıkarmak için z, gösterimini olarak kullanın __real__ z. Benzer şekilde, hayali kısmı çıkarmak için __imag__on niteliğini kullanın z.

Örneğin;

__complex__ float z;
float r;
float i;
r = __real__ z;
i = __imag__ z;

r "z" karmaşık sayısının gerçek kısmıdır i, "z" karmaşık sayısının sanal kısmıdır.


2
Bunlar gcc'ye özgü uzantılardır. Başka bir cevap daha önce onlardan bahsetti ve kabul edilen cevap standart C'de bunun nasıl yapılacağı zaten kabul edildi .
Keith Thompson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.