1)
Sum := 0;
for J in 1 .. N loop
Sum := Sum + J;
end loop;
2)
Sum := ((N + 1) * N) / 2;
我读过第一个(左)解决方案比第二个(右)解决方案更“通用” - 适用于广泛的值。“一般”是什么意思 - 可以计算而不会溢出?
1)
Sum := 0;
for J in 1 .. N loop
Sum := Sum + J;
end loop;
2)
Sum := ((N + 1) * N) / 2;
我读过第一个(左)解决方案比第二个(右)解决方案更“通用” - 适用于广泛的值。“一般”是什么意思 - 可以计算而不会溢出?
我认为“更一般”必须意味着“可以计算出更大范围的数字而不会溢出”。
(2) 中的中间乘积将在 2^31 - 1 处溢出(对于大多数现代机器上的 32 位Integer
),这意味着最大的合法结果将略小于 2^30 - 1。( 1)会让你继续几乎一样远(如果你能等那么久!)
该计划探讨了以下限制:
with Ada.Exceptions;
with Ada.Text_IO; use Ada.Text_IO;
procedure Summation is
N : Integer := 1;
Sum : Integer;
begin
loop
Put (Integer'Image (N) & " => ");
Sum := ((N + 1) * N) / 2;
Put_Line (Integer'Image (Sum));
N := N + 1;
end loop;
exception
when E : others =>
Put_Line (Ada.Exceptions.Exception_Message (E));
end Summation;
如果你编译gnatmake -gnato summation.adb
并运行它,它会以
46337 => 1073581953
46338 => 1073628291
46339 => 1073674630
46340 => 1073720970
46341 => summation.adb:9 overflow check failed
如果您省略-gnato
, 以便 GNAT 不进行数字溢出检查(令人遗憾的默认设置,我记得为了提高效率而选择),就会发生这种情况:
46337 => 1073581953
46338 => 1073628291
46339 => 1073674630
46340 => 1073720970
46341 => -1073716337
46342 => -1073669995
46343 => -1073623652
我想你可以通过在进行乘法之前将任何一个N
和是偶数(显然必须是!)除以 2 来获得更长的范围。N + 1
这并不是一个真正的 Ada 问题(尽管-gnato
它比其他一些语言更容易看出什么时候出错了),而且它肯定不是一个阶乘!可以编辑标题吗?
除了语法(我们在概念上而不是在语法上看这个),
既然我们在这里真的在谈论求和,我将对此作出回应。
我的第一个猜测为什么左边更一般可能是因为大多数人忘记了从 1 到 n 的 i 总和的捷径。因为这两个方程在数学上是等价的。在您的系统上哪一个更快?
一个人完成了将每个单独的数字从 1 添加到 n 的繁琐任务。
如果你看一下维基百科上的求和文章,你会发现从 1 到 100 的求和需要 99 次加法。 http://en.wikipedia.org/wiki/Summation
而右边的等式(快捷方式)只会进行除法和乘法以及单次加法。
我的第二个猜测可能是在某些(可能更多)情况下,添加 n 会更快......这是一个依赖于系统的情况,以及依赖于问题的情况,所以我认为这不太可能。
您能否提供有关此文档的参考,上下文将非常有帮助。