qf_math
Quick Float Math — compact, dependency-free C99 float routines as a practical stand-in for vendor libm where flash and predictable cost matter.
Use it when you already work in IEEE-754 single precision and want table-driven trig, logarithms, exponentials, sqrt, hypot, waveform helpers, and an ADSR envelope from one translation unit. Headers document worst-case error targets; the bench below scores each function against C double references and times the matching *f libm calls.
Repo: github.com/deftio/qf_math · No FPU? Sister library fr_math (fixed-point, same conceptual API family).
Accuracy & speed sweep vs libm
This table is generated by tools/qf_math_bench.c --html-table (same grids as make bench). Numbers are from the machine that last ran make docs-pages or the GitHub Actions Pages deploy — not MCU timings.
Accuracy sweep vs libm (float)
| Function | Bench note | Max | Mean | qf ms | libm ms | libm ÷ qf |
|---|---|---|---|---|---|---|
qf_sin() | radians; ref = sin in double | 0.001885% amp | 0.0007992% amp | 10.64 | 21.39 | 2.01× |
qf_cos() | radians; ref = cos in double | 0.001887% amp | 0.0008006% amp | 10.46 | 22.70 | 2.17× |
qf_tan() | excludes inputs within 0.05 rad of poles | 0.4535% amp | 0.02151% amp | 29.42 | 28.64 | 0.97× |
qf_acos() | domain [-1, 1]; radians out | 0.01482% of pi | 0.002432% of pi | 94.05 | 22.36 | 0.24× |
qf_atan2() | swept (y,x) magnitudes; ref = atan2 double | 0.04097% of pi | 0.01276% of pi | 28.63 | 25.71 | 0.90× |
qf_log2() | x in (0.001, 100]; absolute Δ vs double | 8.104e-07 abs | 2.15e-07 abs | 19.19 | 22.23 | 1.16× |
qf_ln() | x in (0.001, 100]; absolute Δ vs double | 6.235e-07 abs | 1.676e-07 abs | 25.55 | 22.30 | 0.87× |
qf_pow2() | relative vs double; libm ref = exp2f | 0.000322% rel | 3.64e-05% rel | 22.48 | 16.13 | 0.72× |
qf_exp() | relative vs double on grid | 0.0003402% rel | 4.163e-05% rel | 25.65 | 16.28 | 0.63× |
qf_sqrt() | relative vs double | 0.0004702% rel | 0.0001786% rel | 16.08 | 6.27 | 0.39× |
qf_hypot() | relative vs double hypot | 0.0004676% rel | 0.0001906% rel | 13.35 | 13.02 | 0.98× |
qf_hypot_fast8() | qf piecewise-linear; timed vs hypotf reference | 0.1372% rel | 0.05112% rel | 22.89 | 13.17 | 0.58× |
Error column: amp = % of ±1 output (sin/cos/tan). rel = max relative error vs double × 100. of pi = absolute radian error as % of π (acos, atan2). abs = absolute Δ vs double on the grid (log2, ln). libm ÷ qf uses total loop time; > 1 means qf_math was faster on this host (microbenchmark only; profile on your MCU).
Caveats (read before trusting the table)
- Host vs embedded: Desktop
sinf/sqrtfare often highly tuned (SIMD, large vendor tables). On Cortex-M, RISC-V, soft-float, or without a divider, the balance shifts—re-profile on your silicon. MCU snapshots (ESP32-S3, Raspberry Pi Pico 2 ARM & RISC-V) live incompare/MCU_BENCHMARK_SNAPSHOT*.md. - Error metrics are mixed by design: amplitude % for trig on ±1 outputs, relative % for
exp/sqrt/hypot, absolute radians scaled to % of π foracos/atan2, and absolute Δ vs double forlog2/lnon the bench grid (see footnote under the table). - Not a standards substitute: Domain edge cases, errno, and full IEEE exception behavior are out of scope—this is firmware-friendly approximation.
- Multi-library compare matrices (libfixmath, fr_math, …) stay in-repo under
compare/— see compare/.
Minimal include
#include "qf_math.h"
qf y = qf_sin(1.0f); /* radians */
qf len = qf_hypot(dx, dy);