Skip to content

Implement various primtive functions for FBig with correct rounding - #79

Merged
cmpute merged 3 commits into
masterfrom
fbig-func
Jun 18, 2026
Merged

Implement various primtive functions for FBig with correct rounding#79
cmpute merged 3 commits into
masterfrom
fbig-func

Conversation

@cmpute

@cmpute cmpute commented Jun 16, 2026

Copy link
Copy Markdown
Owner

No description provided.

Jacob Zhong and others added 3 commits June 17, 2026 01:01
Add the cubic root (CubicRoot for FBig, Context::cbrt) and the general
nth root (FBig::nth_root, Context::nth_root) to dashu-float, mirroring
the existing sqrt and building on UBig::nth_root.

The general nth_root follows sqrt's structure: shift the significand so
the exponent is divisible by n and it carries at least n*precision
digits, take the integer nth root, then round the last digit. Correct
last-ulp rounding for arbitrary n uses an exact scaled comparison in
the rounding closure:

  frac < 1/2  <=>  2^n * full < (2*root + 1)^n * BASE^low_digits

which reduces exactly to sqrt's remainder test when n == 2. The
expensive (2*root+1)^n term is evaluated only for the half-rounding
modes.

Notable details:
- Short-circuit zero input, since UBig::ZERO.nth_root(n) returns ONE.
- Support negative inputs for odd n (cbrt(-8) = -2); panic on even n
  of a negative, and on n == 0.
- Use the stricter exactness test (rem == 0 && low == 0).
- Add panic_root_zeroth to the error module (mirrors dashu-int).

Tests cover exact and inexact cases for both bases, the n == 2 path
cross-checked against sqrt (value and rounding flag), odd roots of
negatives, panic cases, and a tight toward-zero bracketing check
(r^n <= x < (r+ulp)^n evaluated at unlimited precision) across several
inputs and degrees.

Co-Authored-By: Claude <noreply@anthropic.com>
Add FBig::quantize(exp: isize) -> Rounded<Self>, the dashu analog of
Python's Decimal.quantize(): it rounds self to the nearest multiple of
BASE^exp using self's type-level rounding mode. This fills the
long-standing `// TODO: implement quantize()` placeholder in convert.rs.

The implementation reuses the existing split-and-round machinery
(split_digits_ref + R::round_fract) shared with trunc/ceil/floor/round:

- A finer-or-equal quantum (exp <= self.exponent) leaves the value
  unchanged and is Exact.
- A coarser quantum rounds off low-order digits and is always Inexact,
  since a normalized significand is never divisible by BASE.

Because dashu floats are normalized, trailing zeros cannot be stored to
literally pin the exponent (unlike Python); instead the result's value is
an exact multiple of BASE^exp and its precision is chosen so that
result.ulp() == BASE^exp, i.e. precision = repr.exponent + repr.digits -
exp. Thus quantize(1.234, -2) -> 1.23 at precision 3, while
quantize(1.234, -10) is exact at precision 11. A result that rounds to
zero gets unlimited precision, matching round().

Tests cover decimal/binary cases, exact and inexact branches with value
and rounding-flag checks, result-precision assertions, mode sensitivity
(HalfAway/Down/Up), negatives, zero, an infinity panic, and a sweep
verifying the ulp == BASE^exp invariant across inputs and exponents.

Co-Authored-By: Claude <noreply@anthropic.com>
For n with small prime factors (2, 3, 5, 7), decompose into a chain
of smaller root operations instead of computing x^{n-1} directly in
Newton's method. E.g. n=10000 → four sqrt + four 5th-root calls,
each computing x^{p-1} (x^4) instead of x^{9999}.

Also add a benchmark suite for exp, ln, powi, nth_root, and powf.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@cmpute
cmpute merged commit fe763c9 into master Jun 18, 2026
12 of 13 checks passed
@cmpute
cmpute deleted the fbig-func branch June 18, 2026 17:52
CokieMiner pushed a commit to CokieMiner/dashu that referenced this pull request Jun 25, 2026
…mpute#79)

* Implement cbrt and nth_root for FBig with correct rounding

Add the cubic root (CubicRoot for FBig, Context::cbrt) and the general
nth root (FBig::nth_root, Context::nth_root) to dashu-float, mirroring
the existing sqrt and building on UBig::nth_root.

The general nth_root follows sqrt's structure: shift the significand so
the exponent is divisible by n and it carries at least n*precision
digits, take the integer nth root, then round the last digit. Correct
last-ulp rounding for arbitrary n uses an exact scaled comparison in
the rounding closure:

  frac < 1/2  <=>  2^n * full < (2*root + 1)^n * BASE^low_digits

which reduces exactly to sqrt's remainder test when n == 2. The
expensive (2*root+1)^n term is evaluated only for the half-rounding
modes.

Notable details:
- Short-circuit zero input, since UBig::ZERO.nth_root(n) returns ONE.
- Support negative inputs for odd n (cbrt(-8) = -2); panic on even n
  of a negative, and on n == 0.
- Use the stricter exactness test (rem == 0 && low == 0).
- Add panic_root_zeroth to the error module (mirrors dashu-int).

Tests cover exact and inexact cases for both bases, the n == 2 path
cross-checked against sqrt (value and rounding flag), odd roots of
negatives, panic cases, and a tight toward-zero bracketing check
(r^n <= x < (r+ulp)^n evaluated at unlimited precision) across several
inputs and degrees.

Co-Authored-By: Claude <noreply@anthropic.com>

* Implement quantize(exp) for FBig

Add FBig::quantize(exp: isize) -> Rounded<Self>, the dashu analog of
Python's Decimal.quantize(): it rounds self to the nearest multiple of
BASE^exp using self's type-level rounding mode. This fills the
long-standing `// TODO: implement quantize()` placeholder in convert.rs.

The implementation reuses the existing split-and-round machinery
(split_digits_ref + R::round_fract) shared with trunc/ceil/floor/round:

- A finer-or-equal quantum (exp <= self.exponent) leaves the value
  unchanged and is Exact.
- A coarser quantum rounds off low-order digits and is always Inexact,
  since a normalized significand is never divisible by BASE.

Because dashu floats are normalized, trailing zeros cannot be stored to
literally pin the exponent (unlike Python); instead the result's value is
an exact multiple of BASE^exp and its precision is chosen so that
result.ulp() == BASE^exp, i.e. precision = repr.exponent + repr.digits -
exp. Thus quantize(1.234, -2) -> 1.23 at precision 3, while
quantize(1.234, -10) is exact at precision 11. A result that rounds to
zero gets unlimited precision, matching round().

Tests cover decimal/binary cases, exact and inexact branches with value
and rounding-flag checks, result-precision assertions, mode sensitivity
(HalfAway/Down/Up), negatives, zero, an infinity panic, and a sweep
verifying the ulp == BASE^exp invariant across inputs and exponents.

Co-Authored-By: Claude <noreply@anthropic.com>

* Accelerate UBig::nth_root for large composite n by factor reduction

For n with small prime factors (2, 3, 5, 7), decompose into a chain
of smaller root operations instead of computing x^{n-1} directly in
Newton's method. E.g. n=10000 → four sqrt + four 5th-root calls,
each computing x^{p-1} (x^4) instead of x^{9999}.

Also add a benchmark suite for exp, ln, powi, nth_root, and powf.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Jacob Zhong <jacob@rimbot.com>
Co-authored-by: Claude <noreply@anthropic.com>
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