レッスンに戻る

与えられた数値までのすべての数値を合計する

重要性: 5

数値の合計 1 + 2 + ... + n を計算する関数 sumTo(n) を書いてください。

例:

sumTo(1) = 1
sumTo(2) = 2 + 1 = 3
sumTo(3) = 3 + 2 + 1 = 6
sumTo(4) = 4 + 3 + 2 + 1 = 10
...
sumTo(100) = 100 + 99 + ... + 2 + 1 = 5050

解答のバリアントを3つ作ってください:

  1. for ループを使ってください。
  2. 再帰を使ってください。n > 1 に対して sumTo(n) = n + sumTo(n-1) となるような。
  3. 等差数列 の式を使ってください。

結果の例です:

function sumTo(n) { /*... your code ... */ }

alert( sumTo(100) ); // 5050

P.S. どの解決策が最も速いでしょう?そして遅いものはどれ?なぜでしょう?

P.P.S. 再帰を使って sumTo(100000) を数えることはできますか?

ループを使った解決策です:

function sumTo(n) {
  let sum = 0;
  for (let i = 1; i <= n; i++) {
    sum += i;
  }
  return sum;
}

alert( sumTo(100) );

再帰を使った解決策です:

function sumTo(n) {
  if (n == 1) return 1;
  return n + sumTo(n - 1);
}

alert( sumTo(100) );

公式: sumTo(n) = n*(n+1)/2 を使った解決策です:

function sumTo(n) {
  return n * (n + 1) / 2;
}

alert( sumTo(100) );

P.S. 当然のことながら、この式は最速の解法です。任意の数 n に対して3つの演算しか使用しません。数学は助けます!

ループのバリアントは速度の点では2番目です。再帰とループのバリアント共に同じ数を合計していますが、再帰にはネストされた呼び出しと実行スタック管理が含まれます。それもまたリソースを取るため、より遅くなります。

P.P.S この規格は、「テールコール(末尾呼び出し)」最適化について説明しています。もし再帰呼び出しが関数の中の最後のものである場合(上の sumTo のように)、外部の関数は実行を再開する必要はなく、その実行コンテキストを覚えておく必要はありません。その場合であれば、sumTo(100000) はカウント可能です。しかし、もしあなたのJavaScriptエンジンがそれをサポートしていない場合は最大スタックサイズを超えたというエラーが発生します。これは、通常、スタックサイズの合計に制限があるためです。