Skip to content

fix(core): BigInt-length ranges and full BigFloat precision in integrate and the cubic cache - #223

Merged
mgyoo86 merged 4 commits into
masterfrom
fix/bigfloat-bigint-support
Oct 17, 2026
Merged

mgyoo86 merged 4 commits into
masterfrom
fix/bigfloat-bigint-support

Conversation

@mgyoo86

@mgyoo86 mgyoo86 commented Oct 16, 2026

Copy link
Copy Markdown
Member

Summary

Problem: arbitrary-precision inputs either failed or silently lost precision in three places.

before after
big.(0:16) ./ 16, big(0):big(16), big(0):big(2):big(32), OneTo(big(17)) grids MethodError build like the Vector twin
PCHIP / Cardinal / Akima / Hermite integrate, ND cubic bounded integrate (BigFloat) error ~1e-18 ~1e-77 (full BigFloat)
cubic_interp on the same grid after setprecision(BigFloat, 512) reused the 256-bit factorization (~1e-78) own 512-bit entry (~1e-155)
  • Cause: (1) these ranges report a BigInt length, but _cached_range took len::Int; (2) the Hermite antiderivative basis _IH10/_IH11 used the Float64 literals -2/3, -1/3; (3) BigFloat precision lives outside the type and isequal ignores it, so 256- and 512-bit grids matched the same cubic cache entry.

Fix: one targeted change each. Float64 is unaffected: bit-identical results, unchanged cache-lookup code.

Changes

  • _cached_range takes len::Integer and stores Int(len) (checked), covering conversion and slicing.
  • _IH00…_IH11 build their coefficients from one(t): Float64 folds to the same constants (bit-identical, no fdiv); Float32 now computes in Float32 instead of widening to Float64 (±1–2 ulp).
  • Cubic autocache: _rcu_lookup also requires _verify_build_context(cache) — true for every cache type (folded away), and for CubicSplineCache{BigFloat} a check of the build-time precision. Each precision keeps and reuses its own entry, as Float32/Float64 do via separate banks.

Performance

No change on the non-BigFloat path: the LLVM IR of _get_*_cache_impl / _lookup_or_insert! is identical before/after for Float64/32/16 (Vector, Range, Periodic), Int grids, Unitful, and Dual; an interleaved BenchmarkTools A/B is within noise with the same allocations (Apple M1 Pro, Julia 1.13). BigFloat keeps the cache's ~1.9× build speedup.

Not covered

  • Rational inputs still promote to float (Rational{BigInt} → BigFloat), as documented in type_promotion_rules.md.

Tests

test/test_bigfloat_support.jl (fails on master): BigInt-length grids vs the Vector twin across methods, one-shot, ND, and slicing; Hermite-family 1D integrate/cumulative and ND cubic bounded integrate at BigFloat precision; per-precision cubic cache entries (Vector, Int grid + BigFloat data, periodic). Passes on Julia 1.10 and 1.13.

…e integrate

Ranges parameterized by a BigInt (`big.(0:16) ./ 16`, `big(0):big(16)`,
`big(0):big(2):big(32)`, `StepRange{Rational{BigInt}}`, `OneTo(big(17))`)
report a BigInt `length`; every method must build them like the Vector
twin (1D, one-shot, ND, `_CachedRange` slicing).

Every Hermite-family slope rule reproduces linear data exactly, so its
integral of x/3 + 1/7 must match the closed form at BigFloat precision
(1D bounded + cumulative, and the ND cubic bounded integrate that shares
the antiderivative basis). Today these sit at ~1e-18.
…ery precision

`_cached_range` pinned `len::Int`, so any range whose `length` follows a
BigInt type parameter threw a MethodError at normalization. The factory
now takes `len::Integer` and stores `Int(len)` (checked), covering fresh
conversion and slicing alike.

The Hermite antiderivative basis `_IH10`/`_IH11` used the Float64
literals `-2/3` and `-1/3`, capping BigFloat integrals at ~1e-18 for
PCHIP/Cardinal/Akima/user-slope 1D integrate and the ND cubic bounded
integrate. Coefficients are now built from `one(t)`: Float64 folds to the
same constants (bit-identical, no fdiv), BigFloat keeps full precision,
and Float32 computes in Float32 instead of widening to Float64.
BigFloat precision is global state outside the type, and `isequal`
ignores it: on a dyadic grid (equal across precisions) a factorization
built at 256 bits is served to a 512-bit build, capping the spline at
~1e-78 instead of ~1e-155. Pin that each precision keeps and reuses its
own entry, for Vector BigFloat grids, Int grids with BigFloat data
(Vector{BigFloat} bank), and the periodic pool.
Float16/32/64 carry their precision in the type, so they never share a
bank. BigFloat is one type for every precision, so 256- and 512-bit
grids landed in the same bank and the `isequal` lookup handed out a
factorization built at the wrong precision.

`_rcu_lookup` now also requires `_verify_build_context(entry.cache)`:
`true` for every cache type (folds away — Float/Range/Periodic/Unitful/
Dual lookup IR is unchanged), and for `CubicSplineCache{BigFloat}`
compares the precision of the build-time `inv_d` with the current
default. A mismatch is a miss that inserts a new entry, so each
precision keeps and reuses its own factorization like the other floats
do. Kept separate from `_verify_cache_match`: that hook dispatches on
(cache, bc), and a BigFloat-cache method there is ambiguous with its
`PeriodicBC{:exclusive}` method.
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

FastInterpolations.jl Benchmarks

ℹ️ The previous comment's numbers were measured on znver3|4c; this run is znver5|4c. Each CPU keeps its own min-merge floor.

All benchmarks (71 total, click to expand)
Benchmark Current: 9fa6aa5 Previous Imm. Ratio Grad. Ratio
10_nd_construct/bicubic_2d 23696 ns 25138.0 ns 0.943 0.937
10_nd_construct/bilinear_2d 243.16 ns 271.4 ns 0.896 0.984
10_nd_construct/phs_2d 676155.7 ns 660962.5 ns 1.023 1.059
10_nd_construct/phs_3d 10081924.2 ns 10901033.3 ns 0.925 0.894
10_nd_construct/tricubic_3d 187073 ns 194822.0 ns 0.96 0.901
10_nd_construct/trilinear_3d 588.08 ns 652.8 ns 0.901 0.929
11_nd_eval/bicubic_2d_batch 962.5 ns 1063.6 ns 0.905 0.93
11_nd_eval/bicubic_2d_scalar 12.91 ns 13.7 ns 0.941 0.969
11_nd_eval/bilinear_2d_scalar 5.5 ns 5.9 ns 0.932 0.971
11_nd_eval/phs_2d_batch 20010.3 ns 19812.7 ns 1.01 0.954
11_nd_eval/phs_2d_scalar 151.22 ns 154.4 ns 0.979 0.92
11_nd_eval/phs_3d_batch 105191.3 ns 104308.6 ns 1.008 0.983
11_nd_eval/phs_3d_scalar 949.44 ns 972.5 ns 0.976 0.987
11_nd_eval/tricubic_3d_batch 1951.9 ns 2103.2 ns 0.928 0.94
11_nd_eval/tricubic_3d_scalar 20.13 ns 21.2 ns 0.948 0.919
11_nd_eval/trilinear_3d_scalar 9.01 ns 9.5 ns 0.947 0.947
12_cubic_eval_gridquery/range_random 1799.54 ns 1967.1 ns 0.915 0.7
12_cubic_eval_gridquery/range_sorted 1791.92 ns 1947.9 ns 0.92 0.699
12_cubic_eval_gridquery/vec_random 2971.7 ns 3203.0 ns 0.928 0.844
12_cubic_eval_gridquery/vec_sorted 1435.38 ns 1602.8 ns 0.896 0.802
13_nd_oneshot_gridquery/bicubic_2d_rand_rand 36716.5 ns 36808.3 ns 0.998 0.926
13_nd_oneshot_gridquery/bicubic_2d_sort_rand 35240.3 ns 35405.2 ns 0.995 0.936
13_nd_oneshot_gridquery/bicubic_2d_sort_sort 34615.4 ns 35279.9 ns 0.981 0.935
13_nd_oneshot_gridquery/bilinear_2d_rand_rand 6146.3 ns 6404.6 ns 0.96 1.006
13_nd_oneshot_gridquery/bilinear_2d_sort_rand 4227.8 ns 4268.8 ns 0.99 1.067
13_nd_oneshot_gridquery/bilinear_2d_sort_sort 3062.44 ns 3415.9 ns 0.897 0.969
14_series_oneshot_batch/constant_inplace_vec_k8_q1000_rand 5600.5 ns 5878.8 ns 0.953 0.785
14_series_oneshot_batch/linear_inplace_vec_k8_q1000_rand 6397.7 ns 7229.8 ns 0.885 0.871
15_gridded_query/cubic_oneshot_2d_40x32 27158.1 ns 27955.0 ns 0.971 0.933
15_gridded_query/cubic_persistent_2d_40x32 4252.4 ns 4381.6 ns 0.971 0.925
15_gridded_query/linear_oneshot_2d_40x32 832.66 ns 860.5 ns 0.968 0.927
15_gridded_query/linear_oneshot_3d_12x10x8 983.88 ns 992.5 ns 0.991 0.925
15_gridded_query/linear_persistent_2d_40x32 818.24 ns 827.3 ns 0.989 0.929
15_gridded_query/linear_persistent_3d_12x10x8 962.44 ns 989.1 ns 0.973 0.922
16_phs/construct_g0100 21428.24 ns 24034.5 ns 0.892 0.959
16_phs/construct_g1000 21293.3 ns 23845.8 ns 0.893 0.964
16_phs/eval_q00001 55.88 ns 54.4 ns 1.028 0.965
16_phs/eval_q00100 5552.02 ns 5846.8 ns 0.95 0.92
16_phs/eval_q10000 545278.7 ns 557251.5 ns 0.979 0.909
16_phs/oneshot_q00001 22253.88 ns 24148.7 ns 0.922 0.984
16_phs/oneshot_q10000 877737 ns 877198.8 ns 1.001 0.891
1_cubic_oneshot/q00001 327.48 ns 316.9 ns 1.034 0.962
1_cubic_oneshot/q10000 19114.9 ns 19522.3 ns 0.979 0.679
2_cubic_construct/g0100 860.1 ns 899.7 ns 0.956 0.927
2_cubic_construct/g1000 8362.7 ns 9259.9 ns 0.903 0.965
3_cubic_eval/q00001 5 ns 5.0 ns 1.0 0.592
3_cubic_eval/q00100 186.08 ns 213.5 ns 0.871 0.702
3_cubic_eval/q10000 17885 ns 19421.2 ns 0.921 0.698
4_linear_oneshot/q00001 13.72 ns 14.1 ns 0.972 1.015
4_linear_oneshot/q10000 11121.8 ns 12369.5 ns 0.899 0.948
5_linear_construct/g0100 18.93 ns 19.2 ns 0.984 0.697
5_linear_construct/g1000 135.61 ns 154.6 ns 0.877 0.948
6_linear_eval/q00001 4.1 ns 4.4 ns 0.932 0.854
6_linear_eval/q00100 119.78 ns 143.2 ns 0.836 0.916
6_linear_eval/q10000 11075.8 ns 12518.8 ns 0.885 0.955
7_cubic_range/scalar_query 3.5 ns 3.7 ns 0.946 0.648
7_cubic_vec/scalar_query 4.8 ns 5.0 ns 0.958 0.873
8_cubic_multi/construct_s001_q100 334.12 ns 353.9 ns 0.944 0.896
8_cubic_multi/construct_s010_q100 2972.7 ns 3165.8 ns 0.939 0.992
8_cubic_multi/construct_s100_q100 26810.6 ns 29990.0 ns 0.894 0.956
8_cubic_multi/eval_s001_q100 248.18 ns 244.4 ns 1.016 0.695
8_cubic_multi/eval_s010_q100 787.8 ns 767.6 ns 1.026 0.852
8_cubic_multi/eval_s010_q100_scalar_loop 1754.26 ns 1695.3 ns 1.035 1.05
8_cubic_multi/eval_s100_q100 6104.3 ns 6069.2 ns 1.006 0.931
8_cubic_multi/eval_s100_q100_scalar_loop 2349.6 ns 2251.3 ns 1.044 0.986
9_nd_oneshot/bicubic_2d 24147.6 ns 24432.7 ns 0.988 0.875
9_nd_oneshot/bilinear_2d 272.02 ns 319.1 ns 0.853 0.941
9_nd_oneshot/phs_2d 804855.7 ns 795733.0 ns 1.011 0.976
9_nd_oneshot/phs_3d 11525404.6 ns 12385423.6 ns 0.931 0.902
9_nd_oneshot/tricubic_3d 186729.8 ns 187544.6 ns 0.996 0.848
9_nd_oneshot/trilinear_3d 453.7 ns 527.8 ns 0.86 0.877

✅ 1 benchmark(s) were flagged but verified as CI noise after 10 re-run(s)

Runner: znver5|4c — AMD EPYC 9V45 96-Core Processor, julia 1.13.2. Times are min-merged and compared only against this same machine's history.

This comment was automatically generated by Benchmark workflow.

@codecov

codecov Bot commented Oct 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.31%. Comparing base (608074d) to head (9fa6aa5).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #223   +/-   ##
=======================================
  Coverage   96.31%   96.31%           
=======================================
  Files         173      173           
  Lines       15560    15562    +2     
=======================================
+ Hits        14986    14988    +2     
  Misses        574      574           
Files with missing lines Coverage Δ
src/core/axis_types.jl 90.90% <100.00%> (ø)
src/core/utils.jl 90.54% <ø> (ø)
src/cubic/cubic_cache_pool.jl 93.41% <100.00%> (+0.05%) ⬆️
src/integral/integrate_fulldomain.jl 98.24% <ø> (ø)
src/integral/integrate_kernels.jl 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mgyoo86
mgyoo86 merged commit 9364a70 into master Oct 17, 2026
27 checks passed
@mgyoo86
mgyoo86 deleted the fix/bigfloat-bigint-support branch October 17, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant