1)
Sum := 0;
for J in 1 .. N loop
Sum := Sum + J;
end loop;
2)
Sum := ((N + 1) * N) / 2;
最初の(左)ソリューションは、2番目(右)のソリューションよりも「一般的」であり、幅広い値に適用できることを読みました。「一般」とはどういう意味ですか?オーバーフローなしで計算できますか?
1)
Sum := 0;
for J in 1 .. N loop
Sum := Sum + J;
end loop;
2)
Sum := ((N + 1) * N) / 2;
最初の(左)ソリューションは、2番目(右)のソリューションよりも「一般的」であり、幅広い値に適用できることを読みました。「一般」とはどういう意味ですか?オーバーフローなしで計算できますか?
「より一般的」とは、「より広い範囲の数値に対してオーバーフローなしで計算できる」ことを意味する必要があると思います。
(2)の中間積は、2 ^ 31-1でオーバーフローします(Integer
ほとんどの最新のマシンで得られる32ビットの場合)。つまり、最大の法的な結果は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
掛け算をする前に、偶数とN + 1
偶数(1つは明らかにそうです!)のどちらかを2で割ることで、より長い範囲を得ることができると思います。
これは実際にはAdaの問題ではありません(ただし-gnato
、他の言語で発生する可能性がある場合よりも、問題が発生した場合に簡単に確認できます)。また、階乗ではありません。タイトルを編集することはできますか?
構文はさておき(これは概念的には構文的にではありません)、
ここでは本当に総和について話しているので、それに応えます。
左がより一般的である理由の私の最初の推測は、おそらくほとんどの人が1からnまでのiの合計へのショートカットがあることを忘れているためです。両方の方程式は数学的に同等であるため。あなたのシステムでどちらが速いですか?
1からnまでの個々の数を追加するという面倒な作業を行います。
ウィキペディアの合計の記事を見ると、1から100までの合計には99の追加が必要であることがわかります。 http://en.wikipedia.org/wiki/Summation
一方、右の式(ショートカット)は、除算と乗算、および単一の加算のみを実行します。
私の2番目の推測は、おそらく特定の(おそらくそれ以上の)状況では、n個の追加を行う方が速いでしょう....これはシステムに依存する状況であり、問題に依存するため、その可能性は低いと思います。
このドキュメントに関するリファレンスを教えていただけますか。コンテキストは非常に役立ちます。