web-dev-qa-db-ja.com

数十億の範囲の数値を因数分解するための適切なアルゴリズムは何でしょうか?

私は現在Python=を学んでいます。私が学んでいることを適用する理由を私に与えるために、私はいくつかの問題で亀裂を抱えています Project Euler

私は現在3位です。これは、この数の最高の素因数を決定することです。

私はおそらく2つのアルゴリズムが必要であると推定しました。1つは素数性を決定するアルゴリズムで、もう1つは数の要因を見つけることです。

だから私は Wiki の記事を読んでいます。使用するのに最適なアルゴリズムとは何か、それをどのように処理するかを決定すること。

しかし、ハードコアな数学ベースのプログラミングを行ってからしばらく経ち、どこかから始めるのに苦労しています。

私はFermatの因数分解法を使用してDivision by Trialを含めて見ていましたが、RSAをクラックするために複雑すぎないようにしたいのですが、問題に適した2つのアルゴリズムがあり、そこに私の質問があります。

素数性のテスト/目の前の問題に適した数の因数分解にどのアルゴリズムを使用しますか?

編集

あなたの回答と洞察をありがとうございました。彼らが最も役に立ちました。アドバイスを通じて、またはオイラーの経験を通じて、役立つものすべてに賛成しました。私が正しいとマークしたものは、正しい方向へのプッシュである適切な出発点を私に与えてくれたので、単に最も有用でした。もう一度ありがとう=)

8
Chris

これらの問題に対する私のアプローチは通常、これです。通常、ブルートフォースナイーブアプローチである、それを解決するための最も単純なアルゴリズムを構築し、それが遅すぎるかどうかを数学的にテスト/図化します。ほとんどの場合、それで十分です。アルゴリズムが十分に効率的になるまで、作業を開始して最適化する明確な出発点がない場合。

プロジェクトオイラーの問題3を解決するための簡単なアルゴリズムを次に示します(Cの場合ですが、Pythonに変換すると簡単です):

#include <stdio.h>
#include <math.h>

int isPrime(int n){
    int i;

    if (n==2)
        return 1;

    if (n%2==0)
        return 0;
    for (i=3;i<sqrt(n);i+=2)
        if (n%i==0)
            return 0;
    return 1;
}

int main(){
    long long int n = 600851475143;
    int i = 3;

    while (i<50000){
        if (isPrime(i))
            if (n%i==0)
                printf("%d\n",i);
        i+=2;
    }
    return 0;
}
5
Daniel Scocco

おそらく他の多くのオイラー問題で再利用するので、因数分解と素数探索(基本的に同じこと)を行うコードを書く価値があります。後の質問のためにコードを改善し、非効率的な素数性テストを調べて、十分に効率的でないことが判明した場合は、今のところ最も簡単なアプローチは次のようにすることです。

  • すべての素数を見つける単純なループを記述します(つまり、各数について、以前に見つかった素数ごとにその分割可能性をテストし、すべてが失敗した場合は、素数のリストに追加します)。
  • 因数分解しようとしている数を各素数で除算して、その数の平方根を求めます。
4
Jack V.

実際、これは数学とコンピュータサイエンスの活発な研究分野です。ウィキペディアの記事は、適切な概要を示しています。

http://en.wikipedia.org/wiki/Integer_factorization

あなたが好き/興味深いアルゴリズムを見つけて、それを試してみてください。

おそらくトレードオフを行う必要があります。「良い」アルゴリズムのほとんどは、本当に理解するためにかなりの数学の背景を必要とします(完全に理解しなくても実装できます)。

どこから始めればよいかわからない場合は、二次篩をお勧めします。

http://en.wikipedia.org/wiki/Quadratic_sieve

非常に数学の知識は必要ありませんが、パフォーマンスは優れています。

4
sleske

Ruby usingtrial division with prime numbers)でProjectEulerの問題を少し前に解決しました。

素数の生成は、実際の因数分解アルゴリズムよりもはるかに重要であることがわかりました。素朴な素数生成アプローチを sieve に置き換えるとすぐに、実行時間は妥当な量になりました。

2
sebastiangeiger

非常にシンプルに保つ...

Xの因数を見つける:私は(n)を2から開始し、Xの平方根の整数(丸めではなく、床)まで作業します。Xをnで除算するとYが生成され、Yは整数です。nとYは要因です。 nの最小値は、Yの最大値になります。

Yの原始性:2からYの平方根までループ(m)し、Y/mが整数かどうかを確認します。そうであれば、Yは素数ではありません。別の要因を見つけるために戻ってください。

MがYの根に当たると、素数になります。見ないで。 Yが答えです。

NがXの根に当たる場合、素因数はありません。

1
pdr

私もPython知識を整えており、私のgithubリポジトリでのプロジェクトオイラーの問題への回答も始めています: https://github.com/rentes/Euler

問題3については、次の前提条件に基づく簡単な解決策をプログラムしました。

1)正の整数nを指定すると、2、3、...、mで除算を開始し、mが素因数であることがわかった場合は、リストに追加します。私はすでに発見された素因数の倍数をリストに加えていません。たとえば、4は2の倍数であるため、4はこのリストに追加されません。

2)次に、リストの各素数を乗算して、nと等しいかどうかを確認します。等しい場合、nのすべての素因数が見つかりました。そうでない場合は、すべての素因数がnに等しくなるか、mがnに達するまで、nを次のm数で除算し続けます。

詳細は https://github.com/rentes/Euler/blob/master/problem3.py を参照してください。私がプログラミングした内容を理解するのに役立つコメントを追加しました。それは単純な解決策であり、最速の解決策ではないと確信していますが、それは機能し、理解するのに十分簡単です。

宜しくお願いします

0
Miguel Rentes

すでに1つの完全なソリューションがあるので、このHaskellのソリューションを投稿します...

--  Problem is to find the largest prime factor of 600851475143
module Factor (testval, bigfactor) where
  testval = 600851475143

  bf' :: Integer -> Integer -> Integer

  bf' f x | (f == x)         = f
          | ((mod x f) == 0) = bf' f (div x f)
          | True             = bf' (f+1) x

  bigfactor :: Integer -> Integer

  bigfactor x | (x <  1) = error "Parameter less than 1"
              | (x == 1) = 1
              | True     = bf' 2 x

基本的に、素数性をテストする必要はありません。見つけた因子を分割する場合(そして繰り返し因子を処理することを確認する場合)、非素因数は小さな素因数の積であるため、非素因数は決して発生しません。

これをGHCiで読み込んで実行しました-瞬時に、合計4(はい、4!)のオイラー問題が解決されました。

0
Steve314