Skip to content

Avoid underflow in exponential wait threshold#656

Merged
mergify[bot] merged 1 commit into
jd:mainfrom
zelinewang:fix/exponential-multiplier-underflow
Jul 15, 2026
Merged

Avoid underflow in exponential wait threshold#656
mergify[bot] merged 1 commit into
jd:mainfrom
zelinewang:fix/exponential-multiplier-underflow

Conversation

@zelinewang

@zelinewang zelinewang commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

wait_exponential can raise ValueError: math domain error instead of returning a wait time when multiplier/max are finite and positive but their ratio underflows to 0.0. It's a regression from the threshold optimization in #654. The fix computes the same threshold as a difference of logarithms so there's no underflowing division.

How narrow this is

Pretty narrow, and I want to be upfront about it. The crash needs max / multiplier to underflow a 64-bit float all the way to 0.0, i.e. multiplier bigger than max by more than ~308 orders of magnitude (wait_exponential(multiplier=1e300, max=1e-100)), or a non-finite multiplier. Everyday configs — max=0, multiplier=0, any realistic seconds/milliseconds values — already go through the existing guards and are untouched.

I ran into it while checking the #654 change for edge cases, not in production. Sending it because it's a genuine regression in a recently merged optimization and the fix is one line with no behavior change for valid input — not because I think it bites many people. Happy for you to close it if it's below the bar.

Root cause

The #654 optimization short-circuits to the cap when the exponent would exceed log(max / multiplier). Forming max / multiplier first can underflow to 0.0 for extreme finite inputs, and math.log(0.0) raises. In that regime the uncapped wait is already past max, so the right answer is just max.

log(max) - log(multiplier) is the same value (log(a/b) = log(a) - log(b)) without the underflowing intermediate, so the early-return optimization still holds for every valid input.

Testing

  • uv run pytest -q → 172 passed, 12 subtests
  • uv run poe lint, uv run poe mypy, uv run reno lint → all pass
  • Added a regression test with finite positive values whose ratio underflows.
  • Checked 2,160 positive boundary combinations against the pre-optimization direct-power result — 0 differences, so valid inputs are unchanged.

@mergify

mergify Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-07-15 08:27 UTC · Rule: default · triggered by rule autoqueue
  • Checks skipped · PR is already up-to-date
  • Merged2026-07-15 08:27 UTC · at fabc9d660febbce797be1a00400efe3a68d7d4a8 · squash

This pull request spent 9 seconds in the queue, including 2 seconds running CI.

Required conditions to merge

@mergify
mergify Bot merged commit c650fb4 into jd:main Jul 15, 2026
9 checks passed
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