Repository navigation
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #476 +/- ##
=======================================
Coverage 95.86% 95.87%
=======================================
Files 68 68
Lines 16675 16697 +22
=======================================
+ Hits 15986 16008 +22
Misses 689 689 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Thanks @FBruzzesi for the contribution :) IMO it makes sense to address Cauchy as a whole here: #471, #472 and #473, including entropy and the sampling transform. Separate commits would keep this reviewable, with shared accuracy tests and benchmarks. This is a useful starting point, but there are still cases where intermediate calculations lose a representable result. The goal for me is accuracy and performance. R/SciPy are useful comparisons, but they also have numerical problems on some of these inputs. I would aim for the closest result to a multiprecision reference and measure execution time before/after. A few concrete things worth covering:
There is also a small rounding failure in the current CDF: let d = Cauchy::new(0.0, f64::from_bits(73)).unwrap();
let observed = d.cdf(-2.0);
let expected = f64::from_bits(12);
Could we add multiprecision-derived fixtures using exact binary64 inputs and report maximum ULP error, correctly rounded counts, incorrect zeros and finite/infinite mismatches? Fixed-parameter monotonicity would also be useful. Please distinguish mathematical error in ULP from integer distance to the rounded reference. The current For performance, could we commit reproducible Criterion benchmarks comparing the parent and this PR under the same conditions? Center, branch boundary, tails, subnormals and mixed inputs would give a useful picture. Keep setup outside timing, black-box inputs/results, and include the compiler, flags, CPU and repeated measurements with uncertainty. Check accuracy separately for My local release measurements were on an Apple M1 Max. They suggested slower mixed CDF/SF workloads, but repeated runs were variable, so I would not attach a fixed slowdown percentage to this. A before/after comparison on your machine is useful here. Comparing the isolated reciprocal-atan kernel with There may still be room to improve both. The ARM64 assembly I inspected repeats the distance subtraction in the central branch and has two divisions in the tail branch. Reusing the distance is worth measuring. Compensated reciprocal-pi multiplication and a small-angle specialization with an error bound are also candidates, but each needs both ULP and runtime results before calling it an improvement. IMO one coherent Cauchy change with this evidence would be much stronger. I would like us to improve accuracy without a material regression in ordinary and mixed workloads. |
Closes #473.
@day01 thanks for suggesting I should give it a try. I asked Claude Opus 5.5 to point me to the scipy and the R implementations:
arctan2(1, -z) / pieverywherepcauchyuses the same split at|z| > 1and the sameatan(1 / |z|)tail, but formszfirst, so it shares the tiny-scale zero.I tried (and measured locally) these alternatives:
atan2everywhere: within one scale it is 1 ulp further from the true value on 11 of the existing exact assertions (mean error 0.31 to 0.39 ulp over 20k points with|z| <= 1). The split keeps those assertions as they are.atan2(scale, d) / piin the tail: same accuracy in the far tail, and at most 0.3 ulp better near the switch point (worst case 1.65 vs 1.96 ulps).atan(scale / d)is 1.15x to 2.5x faster per call.Comparison
Relative error against mpmath (50 digits, each input taken as the exact
f64):pcauchycdf(-100)cdf(-1e12)cdf(-1e16)cdf(-1e300)sf(1e300)cdf(-1e10),scale = 1e-300The last row's true value is subnormal (3.18e-311), where f64 spacing limits any result to about 7.8e-14 relative; this PR returns the closest f64 (4.4e-14 off). R and SciPy both divide by the scale first, so both return 0.0 there.
Note that if
x - locationitself overflows (both near ±f64::MAX), the result is still0.0or1.0, the same as R and SciPy.Summary by CodeRabbit