qf_math

Quick Float Math — fast approximate float routines for ARM Cortex-M, RISC-V, Xtensa/ESP32, and any target with IEEE-754 single precision. Trig, log, exp, sqrt, hypot, waveform generators, and ADSR envelope in one translation unit — no dependencies, no libm required.

Browse the docs

Source & benchmarks

github.com/deftio/qf_math — source, tests, multi-library comparison harness, MCU benchmark snapshots (ESP32-S3, Pico 2 ARM & RISC-V).

See BENCHMARK_REPORT.md and BENCHMARK_CROSSPLATFORM.md for full comparison matrices.

Sister library: fr_math (fixed-point)

No hardware FPU? Use fr_math — same API family, pure integer math, 16-bit platform support. Same function coverage, different numeric domain.

Accuracy vs libm

Peak error measured against C double reference over 8000-sample grids. These numbers are architecture-independent — the same lookup tables produce the same errors on every target.

FunctionMetricPeak error
qf_sin()% of full-scale (±1)0.0019%
qf_cos()% of full-scale (±1)0.0019%
qf_tan()absolute0.30
qf_asin()absolute radians0.00047
qf_acos()absolute radians0.00047
qf_atan2()absolute radians0.0013
qf_log2()relative %0.0016%
qf_exp()relative %0.00034%
qf_sqrt()relative %0.00047%
qf_hypot()relative %0.00047%
qf_pow()relative %0.00038%

Speed vs libm — on real MCUs

Ratio of libm wall-clock time to qf_math time for the same function. > 1 = qf_math is faster. Data from compare/ benchmark snapshots using benchmark_core.c on real hardware.

FunctionESP32-S3
(Xtensa, FPU)
Pico 2 ARM
(Cortex-M33)
Pico 2 RISC-V
(Hazard3)
qf_sin()4.30×3.25×4.10×
qf_cos()4.39×2.95×3.95×
qf_tan()3.56×2.59×5.45×
qf_atan2()2.65×0.71×1.93×
qf_log2()2.49×0.94×1.91×
qf_exp()1.55×0.51×1.86×
qf_sqrt()1.07×16.81×0.96×
qf_hypot()2.56×12.26×1.63×
qf_pow()2.36×2.43×2.87×

Microbenchmark ratios from compare/QF_MATH_ARCH_SPEED.md. sqrt is hard to beat on cores with a hardware VSQRT instruction. Full multi-library comparison (libfixmath, fr_math, FastTrig, ESP-DSP) in BENCHMARK_CROSSPLATFORM.md.

Minimal include

#include "qf_math.h"

qf y   = qf_sin(1.0f);       /* radians */
qf len = qf_hypot(dx, dy);
qf dB  = 20.0f * qf_log10(v / ref);