Considering Complex Numbers in PHP

A conversation on Twitter prompted me to write a very rubbish complex number type in PHP. But this got me to thinking about why there are libraries for complex numbers, and why they are not just native types.

Implementing such a system in a native way is conceptually quite simple. For this little thought experiment, I'm going to use PHP. Just because. The starting point is somewhat circular. It doesn't matter so much where you start, but it has to be somewhere. My choice would be a special constant, which is part of the native number type. Because it's PHP, we would call it M_I, which would be i, the square root of -1. We then need two functions to start us off: real_part, and imaginary_part. Some things just have to have an axiomatic definition.

These are all we need to define the complex conjugate:


<?php

function complex_conjugate($z) {
    return real_part($z) - M_I * imaginary_part($z);
}

This lets us define the modulus and argument:


<?php

function complex_modulus($z) {
    return sqrt($z * complex_conjugate($z));
}

function complex_argument($z) {
    if ($z === 0) return null;
    if (real_part($z) < 0 && imaginary_part($z) === 0) return M_PI;
    
    return 2 * atan(
        imaginary_part($z) / 
        (complex_magnitude($z) + real_part($z))
    );
}

In the above case, the argument to sqrt is guaranteed to be a positive real number, so we don't have to worry about issues. But we do need a complex square root:


<?php

function sqrt($z) {
    $r = complex_modulus($z);
    $arg = complex_argument($z);
    
    if ($r === 0) return 0;
    
    return real_sqrt($r) * exp(M_I * $arg / 2);
}

This is the first time I've chosen to redefine an existing function. My reasoning for this is that complex numbers ought to be as transparent as possible, so while functions pertaining only to complex numbers have the "complex_" prefix, a programmer should only have to call one function to get the square root of any number.

Note that we must keep the real one around, though, or else include the algorithm for computing real square roots inside this function.

Now we can take the square root of anything, and get an answer. Although we used the exponential function. Better make sure that's defined:


<?php

function exp($z) {
    $re = real_part($z);
    $im = imaginary_part($z);
    
    $r = real_exp($r);
    $arg = $im;
    
    return $r * (cos($arg) + M_I * sin($arg));
}

function log($z) {
    $r = complex_magnitude($z);
    $arg = complex_argument($z);
    
    return real_log($r) + M_I * $arg;
}

I don't know if such a thing is possible inside PHP, but I might take a look and see if I can figure out how to write a PHP extension that does just this. Mostly I'm not sure how it reacts to overwriting function definitions. Perhaps I would have to namespace them all.

Who knows?