Skip to content

Commit

Permalink
refactor:(ApproxRoot) refact ApproxRoot() for better read and perform…
Browse files Browse the repository at this point in the history
…ance
  • Loading branch information
xusong authored and xusong committed Oct 11, 2024
1 parent e84c0eb commit b01fb42
Showing 1 changed file with 27 additions and 11 deletions.
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
}
}

return guess, nil
Expand Down

0 comments on commit b01fb42

Please sign in to comment.