Skip to content

Cfloat — Complex Number Arithmetic

Overview

A lightweight tiny_cfloat_t complex type and arithmetic for MCU environments. Level 2 in the TinyMath dependency chain.

Header: #include "tiny_cfloat.h"


Why a Custom Complex Type?

ESP32-S3 has no hardware complex-number support. The standard <complex.h> type is heavy (8–16 bytes) and pulls in slow math library dependencies. tiny_cfloat_t is a plain struct:

typedef struct { float re; float im; } tiny_cfloat_t;  // exactly 8 bytes

The inline constructor tiny_cf(re, im) has zero allocation overhead:

static inline tiny_cfloat_t tiny_cf(float re, float im)
{ tiny_cfloat_t z = {re, im}; return z; }

API Reference

Function Operation Complexity
tiny_cf_add(a, b) \((a_r + b_r,\; a_i + b_i)\) \(O(1)\)
tiny_cf_sub(a, b) \((a_r - b_r,\; a_i - b_i)\) \(O(1)\)
tiny_cf_mul(a, b) \((a_r b_r - a_i b_i,\; a_r b_i + a_i b_r)\) \(O(1)\), 4 mul + 2 add
tiny_cf_div(a, b) \(\dfrac{a \cdot \overline{b}}{\|b\|^2}\) \(O(1)\), Smith's robust algorithm
tiny_cf_conj(a) \((a_r,\; -a_i)\) \(O(1)\)
tiny_cfloat_t z1 = tiny_cf(3.0f, 4.0f);
tiny_cfloat_t z2 = tiny_cf(1.0f, 2.0f);

tiny_cfloat_t sum = tiny_cf_add(z1, z2);  // (4, 6)
tiny_cfloat_t prod = tiny_cf_mul(z1, z2); // (−5, 10)
Function Operation Notes
tiny_cf_from_polar(r, θ) \((r \cos\theta,\; r \sin\theta)\) Polar → Cartesian
tiny_cf_abs(z) \(\sqrt{z_r^2 + z_i^2}\) Saturates to 0 for \((0,0)\)
tiny_cf_arg(z) \(\operatorname{atan2}(z_i, z_r)\) Returns 0 for \((0,0)\)
tiny_cf_sqrt(z) \(\sqrt{z}\) (principal branch) Uses \(z_r \pm i\sqrt{\frac{\|z\| - z_r}{2}}\)
tiny_cf_log(z) \(\ln\|z\| + i \arg(z)\) Saturates to \(-\infty\) for near-zero inputs
tiny_cfloat_t z = tiny_cf(0.0f, 1.0f);          // i
float mag = tiny_cf_abs(z);                      // 1.0
float arg = tiny_cf_arg(z);                      // π/2
tiny_cfloat_t sqrt_i = tiny_cf_sqrt(z);          // (0.707, 0.707)

Division: Smith's Algorithm

tiny_cf_div uses Smith's robust algorithm to avoid overflow:

if (|b.re|  |b.im|) {
    k = b.im / b.re
    result = (a.re + k·a.im) / (b.re + k·b.im)  +  i·(a.im  k·a.re) / (b.re + k·b.im)
} else {
    k = b.re / b.im
    result = (a.re·k + a.im) / (b.im + k·b.re)  +  i·(a.im·k  a.re) / (b.im + k·b.re)
}

This avoids the intermediate \(|b|^2\) computation that can overflow for large-magnitude denominators.

Division by Near-Zero

If |b| is below TINY_MATH_MIN_POSITIVE_INPUT_F32 (\(10^{-12}\)), the function returns \(\pm\) TINY_MATH_LARGE_VALUE_F32 as a sentinel.


Return Values

All functions return results by value (not by pointer), making composition natural:

tiny_cfloat_t z = tiny_cf_sqrt(tiny_cf_add(a, b));