Skip to content

Round at up to 38 decimal places instead of 18 - #35

Merged
christianparpart merged 4 commits into
masterfrom
fix/rounding-places-38
Oct 8, 2026
Merged

christianparpart merged 4 commits into
masterfrom
fix/rounding-places-38

Conversation

@christianparpart

Copy link
Copy Markdown
Member

Rounding refused any place outside -18 to 18, a limit left over from the 64-bit Rational. Since Rational holds Int128 and from_decimal spans 10^-38 to 10^38, that limit made checked_round(v, SignificantDigits { 15 }, mode) fail for every value below 1e-4. Rounding now reaches 38 places in each direction; text output keeps its own 18-place limit.

Fixes #34

Changes

  • One limit for all rounding math. New public MaximumDecimalPlaces (38) is the bound for checked_round (both overloads), round_wide_ratio (and so rounded_in_unit, decide_rounding, rounded_output), rounded_sqrt and the rounded logarithms and exponential. An intermediate that does not fit is still Overflow, never a clamped value: an irrational square root stops at 19 places, a logarithm the kernel computes at 36, 2/3 at 38 places does not fit.
  • Transcendental kernel widened from 384 to 448 bits, which a negative exponential at negative places needs once decide_rounding scales by up to 10^38. Constant-evaluation cost per enclosure rises 10 to 15 percent; every compile-time test still fits the default budgets of cl, clang-cl, g++-14 and clang++.
  • rounded_exp correctness at more than 18 places. Its shortcut for very negative arguments (answer 0 or one unit) started below -43, which is only right up to 18 places; at 22 places e^-50 read 0 instead of 2e-22. The shortcut now starts below -89 and the kernel covers -89 up, with the error bound restated. Tests pin the threshold from both sides.
  • Text output stays at 18 places, now stated as its own limit: decimal_text, number_text, traces, render() and std::format behave as before, guarded by their own checks rather than by checked_round refusing.
  • Docs and tests. rational_from_double's documented limits recomputed and pinned on both sides; the round_wide_ratio agreement test extended to -38..38; the guides and the changelog updated.

Christian Parpart added 4 commits October 8, 2026 10:53
Every rounding path refused a place outside -18 to 18, the largest power of
ten in a 64-bit integer. Rational has held Int128 since 0.4.0, and
from_decimal and _r span 10^-38 to 10^38, so checked_round with
SignificantDigits failed for every value below 10^(n - 19): 15 significant
digits of anything below 1e-4.

MaximumDecimalPlaces, 38, is now the one limit checked_round (both forms),
round_wide_ratio, and with it rounded_in_unit and decide_rounding, and
rounded_square_root refuse past. An intermediate that does not fit is still
Overflow, never a wrong or clamped value: 2/3 at 38 places, an irrational
square root past 19 places. checked_decimal_text keeps refusing fewer than
-18 places on its own, which it used to inherit from checked_round.

rational_from_double's documented limits are recomputed and pinned on both
sides: a double below 2^53 rounds at every place up to 22, a fraction over
at least 2^N up to 31.

Refs #34

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
rounded_ln, rounded_log10 and rounded_exp now take places from -38 to 38,
as checked_round does. decide_rounding scales an end by up to 10^38, so the
transcendental kernel widens from 384 to 448 bits: e^-80 to whole 10^38s
scales the denominator 2^(192+116) past 2^384.

The exponential's shortcut below -43 assumed e^x was below a quarter of the
last kept unit at any place accepted, which holds only up to 18 places: at
22 places e^-50 is 2e-22, not 0. The shortcut now starts below -89, the
argument whose exponential is below a quarter of 10^-38, and the kernel's
reduction takes arguments down to -89 (m up to 129); the error bound and
the width bounds in the kernel's comment are restated for it.

A logarithm's enclosure is at least 1.6e-37 wide, so a logarithm rounded
at 37 or 38 places is Overflow, never a guess; up to 30 places the
reference table decides every row. The documented constant-evaluation
costs are re-measured: 10 to 15 percent more per enclosure.

Refs #34

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
Text output keeps refusing more than 18 decimal places either way: fixed
64-bit digit buffers, long division and the compile-time format-spec
checks. Its comments said that limit was checked_round's, or the -18 to 18
DecimalPlaces spans; rounding now reaches 38, so they state it as the text
layer's own. format.hpp's two bare 18s name ExactDecimalPlaces. No
behaviour changes.

Refs #34

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
The numbers guide states the new rounding limit and recomputes the limits
rational_from_double meets; the expressions guide gives the rounded
logarithms' and exponential's places, the logarithms' 36-place ceiling and
the exponential's threshold at -89, and the exact log10 range of 10^-38 to
10^38 the code has. The display guide and the numeric-headroom page keep 18
places as text output's own limit. The changelog records both, and
MaximumDecimalPlaces.

Refs #34

Signed-off-by: Christian Parpart <c.parpart@lastrada.net>
@christianparpart
christianparpart marked this pull request as ready for review October 8, 2026 10:30
@christianparpart
christianparpart merged commit ad87803 into master Oct 8, 2026
15 checks passed
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.

checked_round refuses more than 18 decimal places, a leftover of the 64-bit Rational

1 participant