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;
}