Immutable class representing complex numbers with comprehensive mathematical operations.
The Complex class provides a complete implementation of complex number arithmetic with support for:
- Basic arithmetic (addition, subtraction, multiplication, division)
- Transcendental functions (exponential, logarithm, power, roots)
- Trigonometric and hyperbolic functions
- Conversion between rectangular (a + bi) and polar (r∠θ) forms
- Epsilon-based equality comparison for floating-point precision
All operations return new instances, maintaining immutability.
private(set) float $realThe real part of the complex number. Read-only from outside the class.
private(set) float $imaginaryThe imaginary part of the complex number. Read-only from outside the class.
private(set) ?float $magnitudeThe magnitude (absolute value or modulus) of the complex number. Automatically computed and cached on first access.
For z = a + bi: |z| = √(a² + b²)
private(set) ?float $phaseThe phase (argument or angle) of the complex number in radians, normalized to the principal value range (-π, π]. Automatically computed and cached on first access.
For z = a + bi: arg(z) = atan2(b, a), then wrapped to (-π, π]
The range excludes -π but includes π, following the standard mathematical convention for complex number arguments.
public function __construct(int|float $real = 0, int|float $imag = 0)Create a new complex number from real and imaginary parts.
Parameters:
$real(int|float) - The real part (default: 0)$imag(int|float) - The imaginary part (default: 0)
Examples:
$z1 = new Complex(3, 4); // 3 + 4i
$z2 = new Complex(5); // 5 + 0i (real number)
$z3 = new Complex(0, 2); // 0 + 2i (pure imaginary)
$z4 = new Complex(); // 0 + 0i (zero)Note: To create a complex number from a string, use the parse() method.
public static function i(): selfGet the imaginary unit (0 + 1i). Returns a cached instance.
Example:
$i = Complex::i();
echo $i; // "i"public static function fromPolar(int|float $magnitude, int|float $phase): selfCreate a complex number from polar coordinates (magnitude and phase).
Parameters:
$magnitude(int|float) - The magnitude (r)$phase(int|float) - The phase angle in radians
Examples:
// Create from magnitude and phase
$z1 = Complex::fromPolar(5, M_PI / 4);public static function parse(string $str): selfParse a complex number from a string. Supports various formats.
Supported formats:
- Real numbers:
"5","-3.14" - Pure imaginary:
"i","j","3i","-2.5j" - Complex (real first):
"3+4i","5-2j","-1+i" - Complex (imaginary first):
"4i+3","-2j+5","i-1" - Whitespace tolerant:
" 3 + 4i ","5 - 2j" - Case insensitive:
"I","J"
Examples:
$z1 = Complex::parse("3+4i");
$z2 = Complex::parse("-2.5j");
$z3 = Complex::parse("i");
$z4 = Complex::parse("4i+3");Throws: FormatException if the string is invalid.
public function isReal(): boolCheck if the complex number is real (imaginary part is zero).
Example:
$z1 = new Complex(5, 0);
var_dump($z1->isReal()); // true
$z2 = new Complex(3, 4);
var_dump($z2->isReal()); // falseThe equal() and approxEqual() methods are provided by the ApproxEquatable trait from the Core package.
public function equal(mixed $other): boolCheck if this complex number exactly equals another value.
Compares both real and imaginary parts using exact equality (===). Returns false for invalid types instead of throwing.
Parameters:
$other(mixed) - The value to compare with (Complex, int, or float)
Returns:
bool- True if exactly equal, false otherwise
Examples:
$z1 = new Complex(3, 4);
$z2 = new Complex(3, 4);
$z3 = new Complex(3.0000000001, 4);
var_dump($z1->equal($z2)); // true (exact match)
var_dump($z1->equal($z3)); // false (not exact)
var_dump($z1->equal(5)); // false (z1 is not real)
// Real Complex numbers can equal int/float
$z4 = new Complex(5, 0);
var_dump($z4->equal(5)); // true
var_dump($z4->equal(5.0)); // true
// Invalid types return false
var_dump($z1->equal('string')); // false
var_dump($z1->equal(null)); // falsepublic function approxEqual(
mixed $other,
float $relTol = Floats::DEFAULT_RELATIVE_TOLERANCE,
float $absTol = Floats::DEFAULT_ABSOLUTE_TOLERANCE
): boolCheck if this complex number approximately equals another value within specified tolerances.
Uses combined relative and absolute tolerance approach, comparing both real and imaginary components separately. Returns false for invalid types instead of throwing.
Parameters:
$other(mixed) - The value to compare with (Complex, int, or float)$relTol(float) - Relative tolerance (default: 1e-9)$absTol(float) - Absolute tolerance (default: PHP_FLOAT_EPSILON ≈ 2.22e-16)
Returns:
bool- True if approximately equal within tolerances, false otherwise
How tolerance works:
- For each component, checks:
|a - b| ≤ max(relTol * max(|a|, |b|), absTol) - Relative tolerance matters for large values
- Absolute tolerance matters for values near zero
- Both components must be within tolerance
Examples:
$z1 = new Complex(3, 4);
$z2 = new Complex(3.00000001, 4.00000001);
// Within default tolerance
var_dump($z1->approxEqual($z2)); // true
// With tight tolerance
var_dump($z1->approxEqual($z2, 1e-15, 1e-15)); // false
// With zero tolerances (exact match required)
var_dump($z1->approxEqual($z1, 0.0, 0.0)); // true
var_dump($z1->approxEqual($z2, 0.0, 0.0)); // false
// Works with real numbers
$z3 = new Complex(5, 0);
var_dump($z3->approxEqual(5.0000001, 1e-6)); // true
// Invalid types return false
var_dump($z1->approxEqual('string')); // falsepublic function neg(): selfGet the negative of this complex number.
Example:
$z = new Complex(3, 4);
$result = $z->neg(); // -3 - 4ipublic function inv(): selfGet the multiplicative inverse (reciprocal).
Example:
$z = new Complex(3, 4);
$result = $z->inv(); // 0.12 - 0.16iThrows: DivisionByZeroError if the number is zero.
public function conj(): selfGet the complex conjugate (negate the imaginary part).
Example:
$z = new Complex(3, 4);
$result = $z->conj(); // 3 - 4ipublic function add(int|float|self $other): selfAdd another value to this complex number.
Example:
$z1 = new Complex(3, 4);
$z2 = new Complex(1, 2);
$sum = $z1->add($z2); // 4 + 6ipublic function sub(int|float|self $other): selfSubtract another value from this complex number.
Example:
$z1 = new Complex(5, 7);
$z2 = new Complex(2, 3);
$diff = $z1->sub($z2); // 3 + 4ipublic function mul(int|float|self $other): selfMultiply this complex number by another value.
Example:
$z = new Complex(3, 4);
$result = $z->mul(2); // 6 + 8i
$z1 = new Complex(1, 2);
$z2 = new Complex(3, 4);
$product = $z1->mul($z2); // -5 + 10ipublic function div(int|float|self $other): selfDivide this complex number by another value.
Example:
$z = new Complex(6, 8);
$result = $z->div(2); // 3 + 4i
$z1 = new Complex(1, 2);
$z2 = new Complex(3, 4);
$quotient = $z1->div($z2);Throws: DivisionByZeroError if dividing by zero.
public function pow(int|float|self $exponent): selfRaise this complex number to a power.
Examples:
$z = new Complex(3, 4);
$result = $z->pow(2); // -7 + 24i
$i = Complex::i();
$result = $i->pow(2); // -1 + 0iSpecial cases:
- z^0 = 1 for any z (including 0 by convention)
- 0^(positive) = 0
- 0^(negative or complex) throws
DomainException
public function roots(int $n): arrayCalculate all nth roots of this complex number.
Parameters:
$n(int) - The degree of the root (must be positive)
Returns:
self[]- Array of n complex roots
Examples:
// Cube roots of 1
$z = new Complex(1);
$roots = $z->roots(3); // Returns 3 roots
// Square roots of -1
$z = new Complex(-1);
$roots = $z->roots(2); // Returns [i, -i]Throws: DomainException if n ≤ 0.
public function sqr(): selfCalculate the square of this complex number.
Example:
$z = new Complex(3, 4);
$result = $z->sqr(); // -7 + 24ipublic function sqrt(): selfCalculate the principal square root.
Example:
$z = new Complex(-1);
$result = $z->sqrt(); // 0 + 1ipublic function exp(): selfCalculate e raised to the power of this complex number.
Example:
$z = new Complex(0, M_PI);
$result = $z->exp(); // -1 + 0i (Euler's identity)public function ln(): selfCalculate the natural logarithm.
Example:
$z = new Complex(3, 4);
$result = $z->ln();Throws: DomainException if the number is zero.
public function log(int|float|self $base): selfCalculate logarithm with specified base using change of base formula: log_b(z) = ln(z) / ln(b).
Example:
$z = new Complex(8);
$result = $z->log(2); // 3 + 0i (log₂(8) = 3)Throws:
DomainExceptionif base is 0 or 1DomainExceptionif the number is zero
public function sin(): self
public function cos(): self
public function tan(): selfCalculate trigonometric functions.
Examples:
$z = new Complex(1, 1);
$sin = $z->sin();
$cos = $z->cos();
$tan = $z->tan();public function sec(): self
public function csc(): self
public function cot(): selfCalculate secant, cosecant, and cotangent functions.
Examples:
$z = new Complex(1, 1);
$sec = $z->sec(); // 1/cos(z)
$csc = $z->csc(); // 1/sin(z)
$cot = $z->cot(); // cos(z)/sin(z)public function asin(): self
public function acos(): self
public function atan(): selfCalculate inverse trigonometric functions.
Examples:
$z = new Complex(0.5);
$asin = $z->asin();
$acos = $z->acos();
$atan = $z->atan();public function asec(): self
public function acsc(): self
public function acot(): selfCalculate inverse secant, cosecant, and cotangent functions.
Examples:
$z = new Complex(2);
$asec = $z->asec(); // acos(1/z)
$acsc = $z->acsc(); // asin(1/z)
$acot = $z->acot(); // atan(1/z)public function sinh(): self
public function cosh(): self
public function tanh(): selfCalculate hyperbolic functions.
Examples:
$z = new Complex(1, 1);
$sinh = $z->sinh();
$cosh = $z->cosh();
$tanh = $z->tanh();public function sech(): self
public function csch(): self
public function coth(): selfCalculate hyperbolic secant, cosecant, and cotangent functions.
Examples:
$z = new Complex(1, 1);
$sech = $z->sech(); // 1/cosh(z)
$csch = $z->csch(); // 1/sinh(z)
$coth = $z->coth(); // cosh(z)/sinh(z)public function asinh(): self
public function acosh(): self
public function atanh(): selfCalculate inverse hyperbolic functions.
Examples:
$z = new Complex(0.5);
$asinh = $z->asinh();
$acosh = $z->acosh();
$atanh = $z->atanh();public function asech(): self
public function acsch(): self
public function acoth(): selfCalculate inverse hyperbolic secant, cosecant, and cotangent functions.
Examples:
$z = new Complex(2);
$asech = $z->asech(); // acosh(1/z)
$acsch = $z->acsch(); // asinh(1/z)
$acoth = $z->acoth(); // atanh(1/z)public function toArray(): arrayConvert to array [real, imaginary].
Example:
$z = new Complex(3, 4);
$array = $z->toArray(); // [3.0, 4.0]public function __toString(): stringConvert to string representation.
Format:
- Real numbers:
"5" - Pure imaginary:
"i","3i","-2i" - Complex:
"3 + 4i","3 - 4i","-3 + 4i","-3 - 4i"
Examples:
echo new Complex(5); // "5"
echo new Complex(0, 1); // "i"
echo new Complex(0, -3); // "-3i"
echo new Complex(3, 4); // "3 + 4i"
echo new Complex(3, -4); // "3 - 4i"Complex numbers can be accessed as arrays:
$z = new Complex(3, 4);
// Read access
echo $z[0]; // 3.0 (real part)
echo $z[1]; // 4.0 (imaginary part)
// Check existence
var_dump(isset($z[0])); // true
var_dump(isset($z[2])); // false
// Cannot modify (immutable)
$z[0] = 5; // Throws LogicException
unset($z[0]); // Throws LogicException$z1 = new Complex(3, 4);
$z2 = new Complex(1, 2);
$sum = $z1->add($z2); // 4 + 6i
$diff = $z1->sub($z2); // 2 + 2i
$product = $z1->mul($z2); // -5 + 10i
$quotient = $z1->div($z2); // 2.2 - 0.4i// Create from polar coordinates
$z = Complex::fromPolar(5, M_PI / 4);
// Access polar properties
echo $z->magnitude; // 5.0
echo $z->phase; // 0.785... (π/4)// e^(iπ) = -1
$z = new Complex(0, M_PI);
$result = $z->exp(); // -1 + 0i
// e^(iτ) = 1
$z = new Complex(0, Floats::TAU);
$result = $z->exp(); // 1 + 0i// Find all cube roots of 8
$eight = new Complex(8);
$roots = $eight->roots(3);
echo $roots[0]; // "2" (the real cube root)
echo $roots[1]; // "-1 + 1.7320508075689i" (-1 + √3 i)
echo $roots[2]; // "-1 - 1.7320508075689i" (-1 - √3 i)
// Verify: each root cubed equals 8
$roots[1]->pow(3)->approxEqual(8); // true$z = new Complex(1, 1);
$sin = $z->sin();
$cos = $z->cos();
// Verify Pythagorean identity: sin²(z) + cos²(z) = 1
$sin2 = $sin->sqr();
$cos2 = $cos->sqr();
$sum = $sin2->add($cos2); // 1 + 0i