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

refactor(math) refactor ApproxRoot() for better read and perf #22226

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions math/dec.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,28 +472,44 @@ func (d LegacyDec) ApproxRoot(root uint64) (guess LegacyDec, err error) {
return absRoot.NegMut(), err
}

// One decimal, that we invalidate later. Helps us save a heap allocation.
scratchOneDec := LegacyOneDec()
if root == 1 || d.IsZero() || d.Equal(scratchOneDec) {
// Special cases
if root == 1 || d.IsZero() {
return d, nil
}

// Handle d == 1 case
if d.Equal(LegacyOneDec()) {
return LegacyOneDec(), nil
}

if root == 0 {
return scratchOneDec, nil
return LegacyOneDec(), nil
}

guess, delta := scratchOneDec, LegacyOneDec()
// Initial guess (could improve with better heuristics)
guess = LegacyOneDec() // start with 1
// Constants
rootDec := LegacyDecFromInt64(int64(root))
rootMinusOne := root - 1

for iter := 0; iter < maxApproxRootIterations && delta.Abs().GT(smallestDec); iter++ {
prev := guess.Power(root - 1)
// Iteratively apply Newton's method
for iter := 0; iter < maxApproxRootIterations; iter++ {
// Compute guess^(root-1)
prev := guess.Power(rootMinusOne)
if prev.IsZero() {
prev = smallestDec
prev = smallestDec // avoid division by zero
}
delta.Set(d).QuoMut(prev)
delta.SubMut(guess)
delta.QuoInt64Mut(int64(root))

// delta = (d / guess^(root-1) - guess) / root
delta := d.Quo(prev).Sub(guess).Quo(rootDec)

// Update guess: guess = guess + delta
guess.AddMut(delta)

// If delta is small enough, break early (convergence)
if delta.Abs().LT(smallestDec) {
break
}
}
Comment on lines +495 to 513
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactored Newton's method improves performance and readability

The iterative application of Newton's method has been streamlined. Simplifying the calculation of delta and adding an effective convergence check with smallestDec enhances both performance and readability. The handling of potential division by zero with prev.IsZero() is appropriate.

Suggestion: To further align with the Uber Golang style guide, consider adding comments explaining the choice of smallestDec to avoid division by zero, and clarifying the convergence criteria.

Code Improvement: You might consider encapsulating the convergence criteria and the division by zero handling into separate helper functions to enhance modularity and readability.


return guess, nil
Expand Down
Loading