diff --git a/src/quic_cc_cubic.c b/src/quic_cc_cubic.c index 51d11b11c..fc21aa0f5 100644 --- a/src/quic_cc_cubic.c +++ b/src/quic_cc_cubic.c @@ -243,13 +243,24 @@ static inline void quic_cubic_update(struct quic_cc *cc, uint32_t acked) c->W_target = path->cwnd; } else { + uint64_t wnd_diff; + /* K value computing (in seconds): * K = cubic_root((W_max - cwnd_epoch)/C) (Figure 2) - * Note that K is stored in milliseconds. + * Note that K is stored in milliseconds and that + * 8000 * 125000 = 1000^3. + * + * Supporting 2^40 windows, shifted by 10, leaves ~13 bits of unused + * precision. We exploit this precision for our NS conversion by + * multiplying by 8000 without overflowing, then later by 125000 + * after the divide so that we limit the precision loss to the minimum + * before the cubic_root() call." */ - c->K = cubic_root(((c->last_w_max - path->cwnd) << CUBIC_SCALE_FACTOR_SHIFT) / (CUBIC_C_SCALED * path->mtu)); - /* Convert to milliseconds. */ - c->K *= 1000; + wnd_diff = (c->last_w_max - path->cwnd) << CUBIC_SCALE_FACTOR_SHIFT; + wnd_diff *= 8000ULL; + wnd_diff /= CUBIC_C_SCALED * path->mtu; + wnd_diff *= 125000ULL; + c->K = cubic_root(wnd_diff); c->W_target = c->last_w_max; }