Skip to content

Latest commit

 

History

History
809 lines (575 loc) · 15.3 KB

File metadata and controls

809 lines (575 loc) · 15.3 KB

Complex

Immutable class representing complex numbers with comprehensive mathematical operations.


Overview

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.


Properties

real

private(set) float $real

The real part of the complex number. Read-only from outside the class.

imaginary

private(set) float $imaginary

The imaginary part of the complex number. Read-only from outside the class.

magnitude

private(set) ?float $magnitude

The magnitude (absolute value or modulus) of the complex number. Automatically computed and cached on first access.

For z = a + bi: |z| = √(a² + b²)

phase

private(set) ?float $phase

The 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.


Constructor

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.


Factory Methods

i()

public static function i(): self

Get the imaginary unit (0 + 1i). Returns a cached instance.

Example:

$i = Complex::i();
echo $i;  // "i"

fromPolar()

public static function fromPolar(int|float $magnitude, int|float $phase): self

Create 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);

parse()

public static function parse(string $str): self

Parse 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.


Inspection Methods

isReal()

public function isReal(): bool

Check 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());  // false

Comparison Methods

The equal() and approxEqual() methods are provided by the ApproxEquatable trait from the Core package.

equal()

public function equal(mixed $other): bool

Check 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));      // false

approxEqual()

public function approxEqual(
    mixed $other,
    float $relTol = Floats::DEFAULT_RELATIVE_TOLERANCE,
    float $absTol = Floats::DEFAULT_ABSOLUTE_TOLERANCE
): bool

Check 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'));  // false

Unary Arithmetic Methods

neg()

public function neg(): self

Get the negative of this complex number.

Example:

$z = new Complex(3, 4);
$result = $z->neg();  // -3 - 4i

inv()

public function inv(): self

Get the multiplicative inverse (reciprocal).

Example:

$z = new Complex(3, 4);
$result = $z->inv();  // 0.12 - 0.16i

Throws: DivisionByZeroError if the number is zero.

conj()

public function conj(): self

Get the complex conjugate (negate the imaginary part).

Example:

$z = new Complex(3, 4);
$result = $z->conj();  // 3 - 4i

Binary Arithmetic Methods

add()

public function add(int|float|self $other): self

Add another value to this complex number.

Example:

$z1 = new Complex(3, 4);
$z2 = new Complex(1, 2);
$sum = $z1->add($z2);  // 4 + 6i

sub()

public function sub(int|float|self $other): self

Subtract another value from this complex number.

Example:

$z1 = new Complex(5, 7);
$z2 = new Complex(2, 3);
$diff = $z1->sub($z2);  // 3 + 4i

mul()

public function mul(int|float|self $other): self

Multiply 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 + 10i

div()

public function div(int|float|self $other): self

Divide 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.


Power Methods

pow()

public function pow(int|float|self $exponent): self

Raise 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 + 0i

Special cases:

  • z^0 = 1 for any z (including 0 by convention)
  • 0^(positive) = 0
  • 0^(negative or complex) throws DomainException

roots()

public function roots(int $n): array

Calculate 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.

sqr()

public function sqr(): self

Calculate the square of this complex number.

Example:

$z = new Complex(3, 4);
$result = $z->sqr();  // -7 + 24i

sqrt()

public function sqrt(): self

Calculate the principal square root.

Example:

$z = new Complex(-1);
$result = $z->sqrt();  // 0 + 1i

Transcendental Methods

exp()

public function exp(): self

Calculate e raised to the power of this complex number.

Example:

$z = new Complex(0, M_PI);
$result = $z->exp();  // -1 + 0i (Euler's identity)

ln()

public function ln(): self

Calculate the natural logarithm.

Example:

$z = new Complex(3, 4);
$result = $z->ln();

Throws: DomainException if the number is zero.

log()

public function log(int|float|self $base): self

Calculate 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:

  • DomainException if base is 0 or 1
  • DomainException if the number is zero

Trigonometric Methods

sin(), cos(), tan()

public function sin(): self
public function cos(): self
public function tan(): self

Calculate trigonometric functions.

Examples:

$z = new Complex(1, 1);
$sin = $z->sin();
$cos = $z->cos();
$tan = $z->tan();

sec(), csc(), cot()

public function sec(): self
public function csc(): self
public function cot(): self

Calculate 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)

Inverse Trigonometric Methods

asin(), acos(), atan()

public function asin(): self
public function acos(): self
public function atan(): self

Calculate inverse trigonometric functions.

Examples:

$z = new Complex(0.5);
$asin = $z->asin();
$acos = $z->acos();
$atan = $z->atan();

asec(), acsc(), acot()

public function asec(): self
public function acsc(): self
public function acot(): self

Calculate 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)

Hyperbolic Methods

sinh(), cosh(), tanh()

public function sinh(): self
public function cosh(): self
public function tanh(): self

Calculate hyperbolic functions.

Examples:

$z = new Complex(1, 1);
$sinh = $z->sinh();
$cosh = $z->cosh();
$tanh = $z->tanh();

sech(), csch(), coth()

public function sech(): self
public function csch(): self
public function coth(): self

Calculate 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)

Inverse Hyperbolic Methods

asinh(), acosh(), atanh()

public function asinh(): self
public function acosh(): self
public function atanh(): self

Calculate inverse hyperbolic functions.

Examples:

$z = new Complex(0.5);
$asinh = $z->asinh();
$acosh = $z->acosh();
$atanh = $z->atanh();

asech(), acsch(), acoth()

public function asech(): self
public function acsch(): self
public function acoth(): self

Calculate 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)

Conversion Methods

toArray()

public function toArray(): array

Convert to array [real, imaginary].

Example:

$z = new Complex(3, 4);
$array = $z->toArray();  // [3.0, 4.0]

__toString()

public function __toString(): string

Convert 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"

ArrayAccess Implementation

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

Usage Examples

Basic Complex Arithmetic

$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

Polar Form Conversion

// 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)

Euler's Identities

// 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

Finding Roots

// 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

Complex Trigonometry

$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

See Also

  • Rational - Exact rational number arithmetic
  • Matrix - Matrix operations (can contain complex-valued computations)
  • Vector - Vector operations
  • Floats - Float utilities including TAU constant and approximate comparison