Skip to content

Commit 81b70a9

Browse files
committed
rate: Avoid precision loss with edge cases
When burst is 1, there would be edge cases we get tokens of 0.9999999999997222 due to float64 multiplication/division rounding out value. So avoid those calculation when 'last' is old enough Fixes golang/go#46579
1 parent f8bda1e commit 81b70a9

File tree

2 files changed

+10
-2
lines changed

2 files changed

+10
-2
lines changed

rate/rate.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time,
370370
// Avoid making delta overflow below when last is very old.
371371
maxElapsed := lim.limit.durationFromTokens(float64(lim.burst) - lim.tokens)
372372
elapsed := now.Sub(last)
373-
if elapsed > maxElapsed {
374-
elapsed = maxElapsed
373+
if elapsed >= maxElapsed {
374+
return now, last, float64(lim.burst)
375375
}
376376

377377
// Calculate the new number of tokens, due to time that passed.

rate/rate_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -476,3 +476,11 @@ func BenchmarkWaitNNoDelay(b *testing.B) {
476476
lim.WaitN(ctx, 1)
477477
}
478478
}
479+
480+
func TestPreciseAllow(t *testing.T) {
481+
lim := NewLimiter(0.00027777777777777778, 1)
482+
lim.tokens = 0.54990492004805558
483+
if !lim.Allow() {
484+
t.Errorf("want ok, got false")
485+
}
486+
}

0 commit comments

Comments
 (0)