我编写了下面的代码大纲,基本上是对一个数组(a)求和,其中每个元素乘以一个值x ^ i:
y = a(0)
i = 0
{y = sum from i=0 to (n-1) a(i) * x^i AND 0 <= n <= a.length} //Invariant
while (i < (n-1))
{y = sum from i=0 to (n-1) a(i) * x^i AND 0 <= n <= a.length AND i < (n-1)}
y = y + a(i)*x^i
i = i + 1
end while
{y = sum from i=0 to (n-1) a(i) * x^i} //Postcondition
请注意,我不希望编译代码 - 这只是代码应该如何工作的合理概述。我需要通过使用跟踪变量来提高代码的效率,因此,链接不变以将所述变量与其余代码桥接起来。这是我被困的地方。在这种情况下追踪什么是有用的?我已经考虑过在每次迭代时都保留和值,但是我不确定这是否有效。如果我能弄明白要追踪什么,我很确定将它与空间联系起来是微不足道的。谁能看到我的算法如何通过跟踪变量得到改善?
答案 0 :(得分:1)
你的不变逻辑有一个一分一秒的问题。这是一个跟踪部分动力操作的修正版本。
// Precondition: 1 <= n <= a.length
// Invariant:
{ 0 <= i < n AND xi = x^i AND y = sum(j = 0..i) . a(j) * x^j }
// Establish invariant at i = 0:
// xi = x^0 = 1 AND y = sum(j=0..0) . a(j) * x^j = a(0) * x^0 = a(0)
i = 0;
xi = 1;
y = a(0);
while (i < n - 1) {
i = i + 1; // Break the invariant
xi = xi * x; // Re-establish it
y = y + a(i) * xi
}
// Invariant was last established at i = n-1, so we have post condition:
{ y = sum(j = 0..n-1) . a(j) * x^j }
计算多项式的更常见和数值稳定的方法是使用Horner的规则
y = 0
for i = n-1 downto 0 do y = y * x + a(i)
答案 1 :(得分:0)
所以你似乎想要最终得到这个:
(a(0)*x^0) + (a(1)*x^1) + ... + (a(n-1)*x^(n-1))
是吗?
我可以看到提高性能的唯一方法是^
操作比*
操作更昂贵。在这种情况下,您可以随时跟踪x^n
变量,将x
乘以每次迭代的值。
事实上,在这种情况下,你可以从数组的末尾开始,然后向后工作,每次乘以x
,产生:
(((...((a(n-1)*x+a(n-2))*x+...)+a(2))*x+a(1))*x)+a(0)
理论上这比每次重新计算x ^ i要快一些,但它不会更快算法。它可能不会快一个数量级。