fix: exec_round should round half away from zero#7400
Conversation
Fossier: Approved by MaintainerApproved by |
Merging this PR will improve performance by ×2.2
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | round_with_precision |
6 µs | 1.3 µs | ×4.6 |
| ⚡ | Simulation | round_high_precision |
6.7 µs | 1.7 µs | ×3.9 |
| ⚡ | Simulation | glob_question_multiple |
1.7 µs | 1.5 µs | +15.9% |
| ⚡ | Simulation | glob_question_single |
1.7 µs | 1.5 µs | +15.82% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing arianfarid:fix/round-half-away-from-zero (3f9802a) with main (c70a032)
Footnotes
-
105 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
|
Hello, The arithmetic approach in this PR diverges from SQLite on values like 2.675: This PR: round(2.675, 2) → 2.68 The cause: Happy to look into a fix that matches SQLite's behavior more closely. |
|
Update: the second commit (3f9802a) resolves the 2.675 divergence I flagged above. The original (f * multiplier).round() / multiplier was wrong. The multiply rounds before round() runs. 2.675 * 100 is exactly 267.5 in f64, so it rounded up to 2.68 (but should return 2.67 in SQLite). The fix recovers the exact error of that multiply with mul_add. This way, the rounding decision is made against the true product rather than its rounded approximation. This matches SQLite on the halfway cases (2.25, 2.675, 0.15, etc.). Note: values past ~15 significant digits could still differ from SQLite, but this is past reliable precision for f64. |
|
/fossier approve |
Description
ROUND(x, d) was using Rust's
format!("{:.N}", f)to perform rounding, which applies round-half-to-even (banker's rounding). SQLite uses round-half-away-from-zero.This resulted in inconsistent rounding results for values halfway between precision.
This fix replaces the string format roundtrip by scaling the input by 10^precision, and using
mul_addto recover the rounding errors in scaling.This also eliminates the per call heap allocation of Rust's
format!approach.Motivation and context
Fixes #5748
Description of AI Usage
Claude Code was used to verify correctness, explore non-naive rounding solutions, and locally establish baseline and post-fix benchmarks.