Skip to content

Fix exponential() #226

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

Merged
merged 5 commits into from
Jun 11, 2025
Merged

Fix exponential() #226

merged 5 commits into from
Jun 11, 2025

Conversation

db47h
Copy link
Contributor

@db47h db47h commented May 10, 2025

Fix various issues in exponential() like:

  • ** 1000 needing over 1600 iterations
  • ** -1000 yielding a very large positive number (2.03931737868e+356)
  • ** 2000 not converging after 2570 iterations

The fix involves scaling down x to [0.5, 1) and expanding the Taylor series with increased precision.

The iteration count is now <= 17 with up to 47 multiplications to scale the result in the worst case.

The results are almost always properly rounded, and off by 1 ulp in the worst case.

I'd like to add a test for this, but because of #225, there is no really clean way to do it.

@db47h db47h force-pushed the exp_fix branch 2 times, most recently from eaea933 to a6eeebf Compare May 11, 2025 23:26
Copy link
Owner

@robpike robpike left a comment

Choose a reason for hiding this comment

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

Thanks, this looks generally good.

Fix various issues in exponential() like:

- ** 1000 needing over 1600 iterations
- ** -1000 yielding a large positive number
- ** 2000 not converging after 2570 iterations

The fix involves scaling down x to [0.5, 1) and expanding the Taylor
series with increased precision.

The iteration count is now <= 17 with up to 47 multiplications to
scale the result in the worst case.
- Optimize bounds check on input value by only checking sign & exponents
- Transform negative arguments using exp(x) = 1/exp(-x)
- Dynamically set target exponent for argument reduction
- Dynamically Set extra precision
- Add comments documenting the above points
- Optimize inner loop with one less multiplication
- Optimize inner loop and result squaring by managing temp values
  manually
- Panic on infinite result
@db47h
Copy link
Contributor Author

db47h commented Jun 7, 2025

Update with f460a05.

Sorry about the substantial changes, but this is however much cleaner and addresses all the points you've raised.

@db47h db47h requested a review from robpike June 7, 2025 17:59
// term < 1 ulp of sum ⇒ term < 0.5 × 2^(sum.exp-sum.prec+1)
// 0 ≤ term < 1 × 2^term.exp ⇒ 2^term.exp ≤ 2^(sum.exp-sum.prec)
// Because of argument reduction, 1 ≤ sum < 1+2^(-k+1) ⇒ sum.exp == 1
if term.Sign() == 0 || term.MantExp(nil) <= sum.MantExp(nil) /* ==1 */ -int(sum.Prec()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Although sum.MantExp(nil) is known to be 1, I've left it just in case I messed up somewhere.

Copy link
Owner

@robpike robpike left a comment

Choose a reason for hiding this comment

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

Only trivia remain. It's looking very good.

@db47h db47h requested a review from robpike June 8, 2025 11:26
Copy link
Owner

@robpike robpike left a comment

Choose a reason for hiding this comment

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

Looking very good.

@db47h db47h requested a review from robpike June 9, 2025 13:15
@db47h
Copy link
Contributor Author

db47h commented Jun 9, 2025

Just a quick note regarding the exit condition of the loop where we check that term < ε. This is not an issue with the Taylor series for exponential but there may be other series for which term will become 0.5^big.MinExp after a number of iterations and stay there. So if we were to apply this optimization to other Taylor series, this should be taken into account (or the fact that |term| has become constant).

Copy link
Owner

@robpike robpike left a comment

Choose a reason for hiding this comment

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

Thanks very much for this, lovely improvement.

@robpike robpike merged commit f3f5b3f into robpike:master Jun 11, 2025
@db47h db47h deleted the exp_fix branch June 11, 2025 21:29
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.

2 participants