Skip to Content
Course content

108: Complex Number Arithmetic with complex.h

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've noticed a recurring pattern when developers first tackle complex numbers in C: they immediately reach for a struct. They'll define a typedef struct { double real; double imag; } Complex; and then spend an hour writing helper functions like complex_add() and complex_multiply(). It feels natural because that's how you'd model a data object, but in C, doing this is actually fighting against the language.

You don't need a custom struct for complex math

The problem with the struct approach is that you lose the ability to use standard mathematical operators. If you use a struct, you can't just write z = a + b;. You're stuck with verbose function calls that make your formulas unreadable. C99 introduced complex.h to fix this, treating complex numbers as a first-class numeric type.

// The "Wrong" way (Manual Structs)
typedef struct { double r, i; } Complex;
Complex add(Complex a, Complex b) {
    return (Complex){a.r + b.r, a.i + b.i};
}

// The C way (complex.h)
#include 
double complex a = 1.0 + 2.0 * I;
double complex b = 3.0 + 4.0 * I;
double complex z = a + b; // This actually works!

In the second example, the compiler knows exactly how to handle the addition. It's cleaner, faster, and looks like the math you saw in a textbook.

Letting the compiler handle the imaginary unit

You'll notice I used I in the example above. This isn't a variable I declared; it's a macro defined in complex.h that represents the imaginary unit $\sqrt{-1}$. When you multiply a real number by I, the compiler treats the result as a complex type.

I should warn you: if you're coming from a language like Python, you might be tempted to try and access the real and imaginary parts using dot notation (like z.real). That won't work here. Because double complex is a built-in type and not a struct, you have to use specific accessor functions.

Extracting components and calculating magnitude

To get the individual pieces of a complex number back out, use creal() and cimag(). If you need the magnitude (the distance from the origin in the complex plane), cabs() is your friend. This is much better than manually typing sqrt(r*r + i*i) every time you need a length.

#include 
#include 

int main() {
    double complex z = 3.0 + 4.0 * I;
    
    printf("Real part: %f\n", creal(z));     // 3.0
    printf("Imaginary part: %f\n", cimag(z)); // 4.0
    printf("Magnitude: %f\n", cabs(z));       // 5.0
    
    return 0;
}

One quick tip: if you're working with float or long double, use the corresponding versions: float complex with crealf(), or long double complex with creall(). Stick to double complex unless you have a very specific memory or precision requirement.




📋 Practical Task

Implementing a Basic Phasor Addition Tool for AC Circuits

In electrical engineering, AC voltages are often represented as "phasors" (complex numbers). Your task is to write a program that calculates the total voltage of two AC sources connected in series.

  • Define two complex numbers representing voltages:
    • V1 = 120.0 + 30.0I
    • V2 = 80.0 - 10.0I
  • Calculate the total voltage V_total = V1 + V2.
  • Calculate the magnitude of the total voltage using cabs().
  • Print the resulting total voltage in the format: Total Voltage: (real + imag I), Magnitude: mag.

Constraint: You must use double complex and the complex.h library. Do not define any custom structs.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.