finish(t):我们按时间完成的概率t。使用线性插值。所以 finish(300) 有 70% 的机会在 290 之前完成,加上 2% 在 290 和 300 之间完成,有 72% 的机会。
现在取消平均需要多长时间?
最后一次取消调用所花费的时间平均为wait(t) / finish(t)。
平均有多少呼叫超时?好吧,概率1-finish(t)至少有一个。概率为(1 - finish(t))^2,至少有 2 个。概率为(1 - finish(t))^3,至少有 3 个,依此类推。对于看起来像的平均超时次数:
(1 - finish(t)) + (1 - finish(t))^2 + (1 - finish(t))^3 + ...
但是几何级数有一个技巧:
r + r^2 + r^3 + ...
= (r + r^2 + r^3 + ...) * (1 - r) / (1 - r)
= ((r - r^2) + (r^2 - r^3) + (r^3 - r^4) + ...) / (1 - r)
= (r + (-r^2 + r^2) + (-r^3 - r^3) + ...) / (1 - r)
= r / (1 - r)
在这种情况下r = 1 - finish(t)。所以...
r / (1 - r)
= (1 - finish(t)) / (1 - (1 - finish(t)))
= (1 - finish(t)) / finish(t)
= 1 / finish(t) - 1
我们等待超时取消 t 次我们取消的次数。因此我们要最小化:
wait(t) + t / finish(t) - t
现在我们知道要计算什么,您可以采用两种方法。第一种是只做一个值表,然后选择最好的一个。但是第二种是希望只有一个最小值,用一种爬山的形式来解决。这是一个简单的策略,可以使用二分搜索的变体来做到这一点。
def minimize (f, x_min, x_mid, x_max, tolerance):
(x_min, x_mid, x_max) = sorted((x_min, x_mid, x_max))
if x_max - x_min < tolerance:
return x_mid
elif x_mid - x_min < x_max - x_mid:
x_mid2 = (x_mid + x_max)/2
if f(x_mid) < f(x_mid2):
return minimize(f, x_min, x_mid, x_mid2, tolerance)
else:
return minimize(f, x_mid, x_mid2, x_max, tolerance)
else:
x_mid1 = (x_min + x_mid)/2
if f(x_mid1) < f(x_mid):
return minimize(f, x_min, x_mid1, x_mid, tolerance)
else:
return minimize(f, x_mid1, x_mid, x_max, tolerance)
print(minimize(lambda x: (x**2 - 2)**2, 0, 1, 2, 0.00001))
(始终知道 3 个点的值,中间值低于其他两个点。每次我们选择 2 个间隔中较大的一个点,并丢弃一个点以保持该值。)