69286


アルゴリズムの問題（[こちら](https://www.freecodecamp.org/learn/javascript-algorithms-and-
data-structures/intermediate-algorithm-scripting/sum-all-primes)）に取り組んでいます。

**与えられた引数以下のすべての素数の合計** を返したいです。  
例えば、

[code]

    sumPrimes(10) //returns 17. (2,3,5,7の合計)
    sumPrimes(20) //returns 77. (2,3,5,7,11,13,17,19の合計)
    sumPrimes(977) //returns 73156.
    
[/code]

下記の私の作ったコードでは、引数(26)までは正しい数を返すのですが、(27)以降おかしくなってしまいます。  
（(27)を素数として認識してしまうようです。）

以下が、私の作ったコードです。

[code]

    function sumPrimes(num) {
      var arr = [];
      for(var a =2; a<=num; a++){
        arr.push(a);    　　　　　　 //ここでまず2～numまでのすべての数字を配列に入れて
        }
    
      for(var i=0; i<=arr.length; i++){  //配列に入れた数字を順番にチェックしていく
        for(var d=2; d<arr[i]; d++){　　　　　//各数字を÷2、÷3、÷4..で割っていき、
           if(arr[i] % d == 0){　　　　　　　　//割り切れる数に出会ったら、
           arr.splice(i, 1); 　　　  　　　　　 //その数字を配列から除く
        　　}
       　}
      }
     return arr.reduce((sum,x) =>sum+x);　　　　//最後に残った配列の数字を合計してreturn
    }
    
[/code]

どの部分が原因かおわかりでしょうか。  
教えていただければ幸いです。  
どうぞよろしくお願いいたします。


CC BY-SA 4.0
2020-08-05T21:37:38.027
69285
2020-08-05T23:13:12.470
40891
question
javascript
与えられた引数以下のすべての素数の合計を返すアルゴリズムの問題について


致命的に問題なのはこの行です。

[code]

           arr.splice(i, 1); 　　　  　　　　　 //その数字を配列から除く
    
[/code]

あなたのコードでは`for(var i=0; i<=arr.length;
i++)`で配列全体を検査している(ついでに言うと「配列全体」なら`i<arr.length`ですが、致命的でないことはあえて無視することにします)のですが、そのループの中で`arr`の中身を変更してしまっています。

例えば、`i == 2`の場合、`arr`の中身は、

[code]

    2, 3, 4, 5, ...
          ^
    
[/code]

ですから、本来`4`が素数かどうかチェックしているわけですが、`d == 2`の時に割り切れるので、配列の一部が削除され、

[code]

    2, 3, 5, ...
          ^
    
[/code]

と言う状態になります。

あなたの記述したループでは、`i == 2`のまま`d ==
3`から割り切れるかどうかのチェックを行うので、配列の中身の`5`と言う数字は`2`で割り切れるかどうかのチェックを受けていないことになります。

つまりあなたのコードは、直前の数字がどの数で割り切れると判断されたのかによって、素数判定の結果が変わってしまうことになります。`5`の場合はたまたまそれでも「素数である」と言う判定になりますが、他の数字の並びの場合に正しい結果になるのかどうかは予測困難です。1ステップずつ丹念に解析すれば、なぜ`27`が正しく素数と判定されないのかが分かるでしょうが、そもそも

### 配列をスキャンするループ内で要素の位置が変わるような操作はしない

ことを心がけた方が良いでしょう。

今回の課題の場合、最終的には合計を求めれば良いので、`0`が`arr`中に存在しても結果には影響を与えませんから、先ほどの行を

[code]

           arr[i] = 0; 　　　  　　　　　 //その数字を配列から除く
    
[/code]

と変更すれば、素数ではなかったと言うことを記録できることになります。

* * *

他にも、「どれか一つの数字で割り切れたらもう素数でないことは確定」⇒「そこで内側のループを中断しても良い」など、改良できる点はいろいろありますが、上記の修正だけで正しい結果が得られるはずです。試してみてください。


CC BY-SA 4.0
2020-08-05T23:13:12.470
69286
2020-08-05T23:13:12.470
13972
69285
answer