我正在从事一个需要大量迭代和计算的项目。我们谈论的是大约 2000 次迭代,每次迭代进行 15 到 40 次不同的计算。这..需要很多时间,我正在努力减少时间。
我将尽可能清楚地解释它是如何工作的。这是针对给定的输入(入口温度、压力、功率等)找到最佳的热交换器解决方案。为此,我必须比较所有不同的板(每个板有不同的尺寸、不同的属性),它们有四个重要的东西:类型(A、B 或混合)、分数(如果类型为 A,如果类型为 B,则为 0,以及 0 到 100 之间的 5 的任意倍数(混合类型的 50 除外)、最小数量和最大数量。
现在假设我们有一个类型为 A 的车牌,最小数量为 7,最大数量为 93。分数将为 100%,因为它是由车牌类型定义的。在这种情况下,我的循环将如下所示:
for ($nb = $plate['nb_min']; $nb <= $plate['nb_max']; $nb += 2) { ... }
这已经进行了 44 次迭代。
如果板的类型是B,则环路将类似。但在混合的情况下(具有相同的最小和最大 nb),我必须这样做:
for ($nb = $plate['nb_min']; $nb <= $plate['nb_max']; $nb += 2) {
for ($frac = 5; $frac <= 95; frac += 5) {
...
}
}
这会导致 792 次迭代。就一个盘子来说,还有很多。
中断迭代的条件(我们在每个板的第一个结果处停止,以便我们的边距最接近 0,并且最便宜的解决方案 - 板越多,解决方案就越昂贵)是如果边距为正并且压差是否在可接受的范围内(用户通过输入定义该范围):
if ($margin > 0 && $dp_prim < $postData['dp_max_prim'] && $dp_sec < $postData['dp_max_sec']) {
// current iteration is added to the array of solutions, loop is broken and we can iterate throught the next plate
}
因此,我很自然地尝试读取每次迭代的所有边距,看看我是否能注意到其中的模式。但失败了,盘子有很大不同,不同数量的盘子的保证金差异永远不会相同。
我的意思是,一个盘子的边距可以是-70,然后在下一次迭代中是-67,然后-60,等等。但是对于另一个盘子,它可以是-70,然后-30,等等。
我注意到的一件事是,板的数量通常处于较高数量的板中。所以我尝试反转循环,从最大 nb 开始,然后向下。它给了我更快的结果,但显然利润率和价格都非常高,因为它不是第一个达到正利润率的解决方案。
我发现的另一个“解决方案”是,如果边距太低,我只是跳过一些迭代。像这样:
if ($margin < -50) {
$nb += 6;
continue;
}
if ($margin < -30) {
$nb += 2;
continue;
}
但是,仍然存在我完全错过最接近 0 的边距的风险。我不知道如何正确减少计算时间/迭代次数,同时仍然获得第一个正边距。
按照用户Martin Brown的建议,我所做的是部分二分搜索。基本上,我获取数组中间的值,对其应用函数,然后根据结果,将顶部或底部数组作为要迭代的新数组。 这个步骤我做了两次,计算时间实际上减半了。
我不能永远这样做,因为按照我的帖子中的建议,我绝对必须找到满足条件的第一个值,并且许多值确实满足它们。