Skip to content

Latest commit

 

History

History
58 lines (49 loc) · 4.33 KB

File metadata and controls

58 lines (49 loc) · 4.33 KB

ULP Alignment Report

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
pdf float64 28 28 0 0 0 numpycpp npy_exp (dlsym) — bit-exact to scipy numpy.exp
pdf 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

Key Takeaways

  1. 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/log via dlsym("npy_exp"), matching scipy's internal numpy math path exactly.

  2. linalg.solve is the only API with non-zero ULP. Eigen3 partialPivLu and LAPACK gesv are fundamentally different LU decomposition algorithms with different pivot choices. Well-conditioned small matrices (2×2, identity) are 0 ULP. Random matrices use ULP tolerance.

  3. 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.

  4. 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.

  5. 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.

  6. Compile flags follow the numpycpp README bit-exact spec: -O2 -ffp-contract=off -msse4.1 -mfma (plus -mavx512f -mprefer-vector-width=256 when AVX-512 available) and -fno-builtin-* guards.