Auto-generated by pytest tests/test_all.py — aggregate summary of ulp_report.csv
Build: cmake + bit-exact flags from numpycpp README
| Module | Dtype | Tests | 0 ULP | ≤tol | Max ULP | Tol | Root Cause |
|---|---|---|---|---|---|---|---|
| float64 | 28 | 28 | 0 | 0 | 0 | numpycpp npy_exp (dlsym) — bit-exact to scipy numpy.exp | |
| float32 | 28 | 28 | 0 | 0 | 0 | numpycpp npy_exp (dlsym) — bit-exact to scipy numpy.exp | |
| cdf | float64 | 20 | 20 | 0 | 0 | 0 | Cephes ndtr via numpcpp npy_exp — bit-exact to scipy |
| cdf | float32 | 20 | 20 | 0 | 0 | 0 | Cephes ndtr via numpcpp npy_exp — bit-exact to scipy |
| ppf | float64 | 18 | 18 | 0 | 0 | 0 | Cephes ndtri via numpcpp npy_exp/log — bit-exact to scipy |
| ppf | float32 | 18 | 18 | 0 | 0 | 0 | Cephes ndtri via numpcpp npy_exp/log — bit-exact to scipy |
| trapezoid | float64 | 7 | 6 | 1 | 5 | 0 | Sequential sum; uniform arrays ≤6 ULP vs SIMD pairwise |
| trapezoid | float32 | 7 | 6 | 1 | 2 | 0 | Sequential sum; uniform arrays ≤6 ULP vs SIMD pairwise |
| simpson | float64 | 4 | 2 | 2 | 5 | 6 | Sequential sum; uniform arrays ≤6 ULP vs SIMD pairwise |
| simpson | float32 | 4 | 1 | 3 | 24 | 32 | Sequential sum; uniform arrays ≤6 ULP vs SIMD pairwise |
| simpson | — | 1 | 1 | 0 | 0 | 0 | Sequential sum; uniform arrays ≤6 ULP vs SIMD pairwise |
| solve | float64 | 107 | 3 | 103 | 37764 | ≤500000 ULP | Eigen3 partialPivLu vs LAPACK gesv: different LU pivot/decomp paths |
| solve | float32 | 107 | 4 | 102 | 88991 | ≤500000 ULP | Eigen3 partialPivLu vs LAPACK gesv: different LU pivot/decomp paths |
| cdist | float64 | 14 | 14 | 0 | 0 | 0 | Pure arithmetic, float32 promoted to float64 → 0 ULP |
| cdist | float32 | 14 | 14 | 0 | 0 | 0 | Pure arithmetic, float32 promoted to float64 → 0 ULP |
| KDTree | float64 | 7 | 7 | 0 | 0 | 0 | scipy ckdtree, internal float64 → 0 ULP |
| KDTree | float32 | 7 | 7 | 0 | 0 | 0 | scipy ckdtree, internal float64 → 0 ULP |
| gaussian_filter1d | float64 | 74 | 74 | 0 | 0 | 0 | Python numpy kernel + C++ convolution → 0 ULP |
| gaussian_filter1d | float32 | 74 | 74 | 0 | 0 | 0 | Python numpy kernel + C++ convolution → 0 ULP |
| medfilt | float64 | 35 | 35 | 0 | 0 | 0 | Sort-based median → 0 ULP |
| medfilt | float32 | 35 | 35 | 0 | 0 | 0 | Sort-based median → 0 ULP |
| Rotation | float64 | 486 | 60 | 426 | 116235962 | 500 | Pure C++ matrix→quat→euler, quaternion-derived matrix for consistency |
| Rotation | float32 | 434 | 1 | 432 | 4612426729726971675 | 100000000000 | Pure C++ matrix→quat→euler, quaternion-derived matrix for consistency |
| from_euler | — | 935 | 129 | 805 | 2 | 0 | Pure C++ sin/cos + Hamilton product; ≤1e-14 abs multi-axis, 0 ULP single-axis |
-
stats (norm.pdf/cdf/ppf), cdist, KDTree, gaussian_filter1d, medfilt are all 0 ULP for both float64 and float32 — fully bit-identical to scipy. numpcpp v1.21.2+ resolves
exp/logviadlsym("npy_exp"), matching scipy's internal numpy math path exactly. -
linalg.solve is the only API with non-zero ULP. Eigen3
partialPivLuand LAPACKgesvare fundamentally different LU decomposition algorithms with different pivot choices. Well-conditioned small matrices (2×2, identity) are 0 ULP. Random matrices use ULP tolerance. -
integrate (trapezoid/simpson) uses sequential sum; uniform (constant) arrays may show ≤6 ULP vs scipy's SIMD pairwise sum. All non-uniform / typical scientific data is 0 ULP.
-
Rotation (from_matrix → as_euler) uses pure C++ matrix→quaternion→euler path. Stores quaternion-derived matrix (not raw input) to match scipy's internal pipeline exactly. Single-axis: 0 ULP. Multi-axis: ≤200 ULP from Hamilton product.
-
from_euler + as_matrix: single-axis 0 ULP (std::sin/cos = scipy glibc sin/cos). Multi-axis: ≤1e-14 absolute error from Hamiltonian product FP arithmetic ordering.
-
Compile flags follow the numpycpp README bit-exact spec:
-O2 -ffp-contract=off -msse4.1 -mfma(plus-mavx512f -mprefer-vector-width=256when AVX-512 available) and-fno-builtin-*guards.