Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Estimation + fixup in dragon4 exact #1

Open
Viatorus opened this issue Feb 17, 2023 · 0 comments
Open

Estimation + fixup in dragon4 exact #1

Viatorus opened this issue Feb 17, 2023 · 0 comments

Comments

@Viatorus
Copy link

Viatorus commented Feb 17, 2023

Hi there,

I try to implement the dragon4 algorithm for another C++ project (https://github.com/Viatorus/emio/) and came across your well structured implementation.

I think I understand the most but the one which doesn't make total sense to me is the estimation of k and the fix up routine.
Maybe you could answer me my question. If not, I'm sorry to have bothered you. I already appreciate your great work!

  1. The estimation function looks really clever, since it doesn't use any double arithmetic:
pub fn estimate_scaling_factor(mant: u64, exp: i16) -> i16 {
    // 2^(nbits-1) < mant <= 2^nbits if mant > 0
    let nbits = 64 - (mant - 1).leading_zeros() as i64;
    // 1292913986 = floor(2^32 * log_10 2)
    // therefore this always underestimates (or is exact), but not much.
    (((nbits + exp as i64) * 1292913986) >> 32) as i16
}

I saw other estimations, which use double arithmetic:
https://github.com/google/double-conversion/blob/256ac809561b756645e73ab7127c2aaaeabaa427/double-conversion/bignum-dtoa.cc#L407-L413
https://github.com/eblot/newlib/blob/a1ee8f65e56ede59738f5d68a12f2cef0774d977/newlib/libc/stdlib/dtoa.c#L356

How would you compare your estimation against other? Where did your implementation idea came from?

  1. Why do we need div_2pow10 for fix up and cannot reduce to something simpler?

// fixup when `mant + plus >= scale`, where `plus / scale = 10^-buf.len() / 2`.
// in order to keep the fixed-size bignum, we actually use `mant + floor(plus) >= scale`.
// we are not actually modifying `scale`, since we can skip the initial multiplication instead.
// again with the shortest algorithm, `d[0]` can be zero but will be eventually rounded up.
if *div_2pow10(&mut scale.clone(), buf.len()).add(&mant) >= scale {
// equivalent to scaling `scale` by 10
k += 1;
} else {

Why must we depend on buf.len() (which is ~826). Couldn't we use the same check from format_shortest?

// fixup when `mant + plus > scale` (or `>=`).
// we are not actually modifying `scale`, since we can skip the initial multiplication instead.
// now `scale < mant + plus <= scale * 10` and we are ready to generate digits.
//
// note that `d[0]` *can* be zero, when `scale - plus < mant < scale`.
// in this case rounding-up condition (`up` below) will be triggered immediately.
if scale.cmp(mant.clone().add(&plus)) < rounding {

Thank you very much in advance!

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

No branches or pull requests

1 participant