Skip to main content

Overview

The math utilities in math_utils.c provide essential operations for fractal calculations:
  • Coordinate system transformations
  • Complex number arithmetic
  • Scaling and mapping functions
All functions are defined in fractol.h and implemented in math_utils.c.

Coordinate Mapping

map()

Maps a value from one range to another using linear interpolation.
fractol.h:84-85
double map(double unscaled_num, double new_min, double new_max, double old_max);
unscaled_num
double
required
The value to map from the old range [0, old_max]
new_min
double
required
Minimum value of the target range
new_max
double
required
Maximum value of the target range
old_max
double
required
Maximum value of the source range (minimum is always 0)

Implementation

From math_utils.c:15-22:
double map(double unscaled_num, double new_min, double new_max, double old_max)
{
    double old_min;

    old_min = 0;
    return ((new_max - new_min) * (unscaled_num - old_min)
        / (old_max - old_min) + new_min);
}

Mathematical Formula

f(x)=(newmaxnewmin)×(x0)oldmax0+newminf(x) = \frac{(new_{max} - new_{min}) \times (x - 0)}{old_{max} - 0} + new_{min} This implements linear interpolation from range [0, old_max] to [new_min, new_max].

Usage Examples

// Maps pixel x-coordinate [0, 2000] to complex real axis [-2, +2]
z.x = map(x, -2, +2, WIDTH);
// With WIDTH = 2000:
// x=0    → -2.0
// x=1000 → 0.0
// x=2000 → +2.0
The source range always starts at 0 (old_min is hardcoded). This simplifies pixel coordinate mapping since screen coordinates start at (0, 0).

Complex Number Operations

sum_complex()

Adds two complex numbers.
fractol.h:83
t_complex sum_complex(t_complex z1, t_complex z2);
z1
t_complex
required
First complex number (x component = real part, y component = imaginary part)
z2
t_complex
required
Second complex number to add

Returns

result
t_complex
Complex number representing z1 + z2

Implementation

From math_utils.c:24-31:
t_complex sum_complex(t_complex z1, t_complex z2)
{
    t_complex result;

    result.x = z1.x + z2.x;
    result.y = z1.y + z2.y;
    return (result);
}

Mathematical Formula

For complex numbers z1=a+biz_1 = a + bi and z2=c+diz_2 = c + di: z1+z2=(a+c)+(b+d)iz_1 + z_2 = (a + c) + (b + d)i

Usage in Fractal Iteration

From fractol_render.c:50:
z = sum_complex(sqare_complex(z), c);
This implements the core fractal formula: zn+1=zn2+cz_{n+1} = z_n^2 + c

sqare_complex()

Function name contains a typo (“sqare” instead of “square”) in the original source code.
Computes the square of a complex number.
fractol.h:82
t_complex sqare_complex(t_complex z);
z
t_complex
required
Complex number to square (x = real part, y = imaginary part)

Returns

result
t_complex
Complex number representing z²

Implementation

From math_utils.c:33-40:
t_complex sqare_complex(t_complex z)
{
    t_complex result;

    result.x = (z.x * z.x) - (z.y * z.y);
    result.y = 2 * z.x * z.y;
    return (result);
}

Mathematical Formula

For complex number z=a+biz = a + bi: z2=(a+bi)2=a2+2abi+(bi)2=(a2b2)+2abiz^2 = (a + bi)^2 = a^2 + 2abi + (bi)^2 = (a^2 - b^2) + 2abi Breaking down the components:
  • Real part: a2b2a^2 - b^2 (difference of squares)
  • Imaginary part: 2ab2ab (twice the product)

Derivation

Example Calculation

t_complex z = {3.0, 4.0};  // 3 + 4i
t_complex result = sqare_complex(z);

// result.x = 3² - 4² = 9 - 16 = -7
// result.y = 2 × 3 × 4 = 24
// Result: -7 + 24i
Verification: (3+4i)2=9+24i+16i2=9+24i16=7+24i(3 + 4i)^2 = 9 + 24i + 16i^2 = 9 + 24i - 16 = -7 + 24i

Usage in Fractal Rendering

These functions work together in the main iteration loop (fractol_render.c:48-58):
Mandelbrot/Julia Iteration
while (i < fractol->iterations_definition)
{
    z = sum_complex(sqare_complex(z), c);  // z = z² + c
    if ((z.x * z.x) + (z.y * z.y) > fractol->escape_value)
    {
        // Point escapes - calculate color
        color = map(i, PSYCHEDELIC_LIME, PSYCHEDELIC_MINT,
                fractol->iterations_definition);
        my_pixel_put(x, y, &fractol->img, color);
        return;
    }
    i++;
}

Step-by-Step Example


Performance Considerations

Magnitude Check Optimization

Instead of calculating x2+y2\sqrt{x^2 + y^2} and comparing to 2, the code compares x2+y2x^2 + y^2 to 4:
// Efficient: No square root needed
if ((z.x * z.x) + (z.y * z.y) > fractol->escape_value)  // escape_value = 4

// Equivalent but slower:
if (sqrt((z.x * z.x) + (z.y * z.y)) > 2.0)
This avoids expensive square root operations across 3 million pixels.

Function Call Overhead

These functions are called millions of times per frame:
  • map(): 2 calls per pixel (6M times per render)
  • sqare_complex(): Up to 30 times per pixel (90M max per render)
  • sum_complex(): Up to 30 times per pixel (90M max per render)
Consider these candidates for compiler inlining or macro optimization in performance-critical builds.

Build docs developers (and LLMs) love