素数、友愛数を求める

以前、こんな記事を書いた。
三冊(チョコレートをたべたさかな、東京タワー、博士の愛した数式) - じゅんじゅんのきまぐれ
この中の「博士の愛した数式」で書いたプログラムについて。
年の瀬にプログラムを改造して、年明けからほとんど動かしっぱなし。
改造前は、素数をひたすら求めるだけ。
1000万まで行くのに、3日程度でしたが、改造後の現在は、
25日くらいで、500万程度。
えらい遅くなったので、早くするアイデアを募集中。
ということで、現在のロジックを書いてみる。
ロジックなんてのは、長く面白くないものであったりします。


随分遅くなったのは、以下の改造のため。
1.全ての素数は、本当に4n-1か4n+1か?
2.双子素数はどの程度発生するか?
3.友愛数を探す
どんな原理か記事にしてみる。

素数を探すだけのアルゴリズム

  1. 素数領域に、2と3を登録する
  2. 最初の検討数を5とする
  3. メイン部:
    1. 検討数が、素数領域にある数で割り切れるか、素数領域にある数全てで検査する
    2. 素数領域の全てで割り切れない場合は、素数とみなし、素数領域に格納し、メイン部を抜ける
    3. 割り切れる数が見つかり次第、メイン部を抜ける
  4. 次へ:
    1. 検討数を+2して、メイン部最初に戻る


解説
2と3は、とりあえず素数
4は素数でない。これは算出しない。
よって、最初の検討数は、5とする。
素数以外で割れるか検討しないのは、必要ないから。
例えば、121で割り切れる数は、121を割り切れる素数、11でも当然割り切れる。
なお、素数領域にある数全てで検査しなくても良い。
正確には、検討数の平方根以下の数、すなわち、検討数が144の場合、12までの素数で検査すれば良い。
次へ、で+2するのは、偶数は検討するまでもないから。
2以外の素数は、奇数のみ。

改造後のプログラム

1.全ての素数は、本当に4n-1か4n+1か?

これは、見つけた素数が、1足して4で割り切れるか、1引いて4で割り切れるか見る。
これを、素数を発見した部分に加えるだけ。
、、、なのですが、、、先日、はたと気付いた。
計算するまでもない!
何故なら、全ての自然数は4で割り切れる数を中心に考えると、
4n, 4n+1, 4n+2, 4n+3 の4つに分類できる。
そして、4n-1 に分類できる数と、4n+3 に分類できる数は同じもの。
ということは、本の中で素数候補とされた数は、4n+1 と 4n+3。
素数候補以外の数は、4n と 4n+2。
4n と 4n+2 は、いずれも、2で割り切れる、、、偶数である、、、。
ということで、4n-1 か 4n+1 か検証ロジックは無駄である。

2.双子素数はどの程度発生するか?

これは、前回発見素数を保持し、今回発見素数との差が2か見るだけ。
ま、大した負荷ではないです。
ちりつも、かもしれませんけどね。

3.友愛数を探す

これが、最大負荷。
まず、+2で検討候補を加算していたのが、+1づつに修正。
それから、友愛数友愛数相方領域を用意する。
(相方と同じ数値の場合、完全数、ということですな。)
素数でない、と判定した後に、友愛数相方領域にあるか確認。
あれば、検出済みで次の数値へ。
なければ、割り切れる値を全て割り出す。(素数以外も)
割り切れる値の場合、それらを加算して回る。
半分までの数値で、割り切れる数を洗い終わったら、加算結果が元の数値より同じか大きいか確認。
同じ場合、完全数として登録。
大きい場合、加算結果の割り切れる数の合計を洗う。
合計値が検討数と同じになったら、友愛数として登録。


重い。
奇数しか検討しない。
素数で割り切れるか確認すれば良い。
それも検討数の平方根まで。
元のプログラムを作るときに思いついた高速化が、全てぱー、です。


うちのPCは、Pen4のHyperthreadテクノロジ。*1
なので、動かしっぱなしでも、特に問題はないですけどね。
ブログ更新中も計算。
メール書いてる間も計算。
OSのUpdate中も計算。
Hyperthreadテクノロジ、デスクトップPCには良いですね。
何かさせつつ、私の相手もしてもらう。
フォン・ノイマンこんぴーた、偉いの。

*1:二つの作業をほぼ同時処理できる技術のこと。計算処理と私の相手と二つの処理、ということ