194

数の最大の素因数を計算するための最良のアプローチは何ですか?

最も効率的なのは次のことだと思います。

  1. きれいに分割する最小の素数を見つける
  2. 除算の結果が素数であるかどうかを確認します
  3. そうでない場合は、次に低いものを見つけます
  4. 2に進みます。

この仮定は、小さな素因数を計算する方が簡単であることに基づいています。これは正しいですか?他にどのようなアプローチを検討する必要がありますか?

編集:結果が他の2つの素数の積である場合、ステップ2は失敗するため、2つ以上の素因数が作用している場合、私のアプローチは無駄であることに気付きました。したがって、再帰的アルゴリズムが必要です。

もう一度編集します。最後に見つかった素数が最大である必要があるため、これが引き続き機能することに気付きました。したがって、ステップ2の非素数の結果をさらにテストすると、素数が小さくなります。

4

29 に答える 29

146

これが私が知っている最高のアルゴリズムです(Pythonで)

def prime_factors(n):
    """Returns all the prime factors of a positive integer"""
    factors = []
    d = 2
    while n > 1:
        while n % d == 0:
            factors.append(d)
            n /= d
        d = d + 1

    return factors


pfs = prime_factors(1000)
largest_prime_factor = max(pfs) # The largest element in the prime factor list

上記の方法はO(n)、最悪の場合 (入力が素数の場合) に実行されます。

編集:コメントで提案されているように、
以下はバージョンです。O(sqrt(n))これがコードです。

def prime_factors(n):
    """Returns all the prime factors of a positive integer"""
    factors = []
    d = 2
    while n > 1:
        while n % d == 0:
            factors.append(d)
            n /= d
        d = d + 1
        if d*d > n:
            if n > 1: factors.append(n)
            break
    return factors


pfs = prime_factors(1000)
largest_prime_factor = max(pfs) # The largest element in the prime factor list
于 2009-01-05T12:18:04.773 に答える
140

実際には、大きな数の約数を見つけるためのより効率的な方法がいくつかあります (小さな数の場合、試行分割はかなりうまく機能します)。

入力数値がその平方根に非常に近い 2 つの因数を持つ場合に非常に高速な 1 つの方法は、フェルマー因数分解として知られています。これは恒等 N = (a + b)(a - b) = a^2 - b^2 を利用しており、理解しやすく実装も簡単です。残念ながら、一般的にはそれほど高速ではありません。

100 桁までの数を素因数分解する最もよく知られている方法は、二次ふるいです。おまけとして、アルゴリズムの一部は並列​​処理で簡単に実行できます。

私が聞いたさらに別のアルゴリズムは、ポラードの Rho アルゴリズムです。一般に Quadratic Sieve ほど効率的ではありませんが、実装するのは簡単なようです。


数値を 2 つの因数に分割する方法を決定したら、数値の最大の素因数を見つけるために考えられる最速のアルゴリズムを次に示します。

最初に番号自体を格納する優先キューを作成します。反復ごとに、キューから最大数を削除し、それを 2 つの要素に分割しようとします (もちろん、1 がそれ​​らの要素の 1 つになることはできません)。このステップが失敗した場合、数は素数であり、答えがあります! それ以外の場合は、2 つの要素をキューに追加して繰り返します。

于 2008-10-28T03:44:38.280 に答える
17

私の答えはTriptychに基づいていますが、それを大幅に改善しています。これは、2と3を超えると、すべての素数が6n-1または6n+1の形式であるという事実に基づいています。

var largestPrimeFactor;
if(n mod 2 == 0)
{
    largestPrimeFactor = 2;
    n = n / 2 while(n mod 2 == 0);
}
if(n mod 3 == 0)
{
    largestPrimeFactor = 3;
    n = n / 3 while(n mod 3 == 0);
}

multOfSix = 6;
while(multOfSix - 1 <= n)
{
    if(n mod (multOfSix - 1) == 0)
    {
        largestPrimeFactor = multOfSix - 1;
        n = n / largestPrimeFactor while(n mod largestPrimeFactor == 0);
    }

    if(n mod (multOfSix + 1) == 0)
    {
        largestPrimeFactor = multOfSix + 1;
        n = n / largestPrimeFactor while(n mod largestPrimeFactor == 0);
    }
    multOfSix += 6;
}

最近、このアルゴリズムがどのように機能するかを説明するブログ記事を書きました。

私は、素数性のテストの必要がない(そしてふるいの構築がない)方法が、それらを使用する方法よりも速く実行されるだろうと思い切って思います。その場合、これはおそらくここで最速のアルゴリズムです。

于 2009-05-06T14:52:12.280 に答える
8

JavaScript コード:

'option strict';

function largestPrimeFactor(val, divisor = 2) { 
    let square = (val) => Math.pow(val, 2);

    while ((val % divisor) != 0 && square(divisor) <= val) {
        divisor++;
    }

    return square(divisor) <= val
        ? largestPrimeFactor(val / divisor, divisor)
        : val;
}

使用例:

let result = largestPrimeFactor(600851475143);

コードの例を次に示します

于 2016-04-01T15:54:37.850 に答える
4

最も単純な解決策は、相互に再帰的な関数のペアです。

最初の関数は、すべての素数を生成します。

  1. 1 より大きいすべての自然数のリストから始めます。
  2. 素数でないすべての数を削除します。つまり、(それ自体以外に) 素因数を持たない数値です。下記参照。

2 番目の関数は、指定された数値の素因数nを昇順で返します。

  1. すべての素数のリストを取得します (上記を参照)。
  2. の因数ではないすべての数を削除しますn

の最大の素因数nは、2 番目の関数によって与えられる最後の数値です。

このアルゴリズムには、遅延リストまたは必要に応じた呼び出しのセマンティクスを備えた言語 (またはデータ構造) が必要です。

明確にするために、Haskellでの上記の(非効率的な)実装の1つを次に示します。

import Control.Monad

-- All the primes
primes = 2 : filter (ap (<=) (head . primeFactors)) [3,5..]

-- Gives the prime factors of its argument
primeFactors = factor primes
  where factor [] n = []
        factor xs@(p:ps) n =
          if p*p > n then [n]
          else let (d,r) = divMod n p in
            if r == 0 then p : factor xs d
            else factor ps n

-- Gives the largest prime factor of its argument
largestFactor = last . primeFactors

これを高速化するには、どの数値が の素数および/または因数であるかをより賢く検出するだけの問題ですnが、アルゴリズムは同じままです。

于 2008-10-28T04:42:40.770 に答える
4

すべての数値は、素数の積として表すことができます。たとえば、次のようになります。

102 = 2 x 3 x 17
712 = 2 x 2 x 2 x 89

単純に 2 から始めて、結果が数値の倍数でなくなるまで除算を続けるだけで、これらを見つけることができます。

712 / 2 = 356 .. 356 / 2 = 178 .. 178 / 2 = 89 .. 89 / 89 = 1

この方法を使用すると、素数を実際に計算する必要はありません。先行するすべての数値で可能な限り因数分解したという事実に基づいて、素数はすべて素数になります。

number = 712;
currNum = number;    // the value we'll actually be working with
for (currFactor in 2 .. number) {
    while (currNum % currFactor == 0) {
        // keep on dividing by this number until we can divide no more!
        currNum = currNum / currFactor     // reduce the currNum
    }
    if (currNum == 1) return currFactor;    // once it hits 1, we're done.
}
于 2008-10-28T05:06:53.013 に答える
4
    //this method skips unnecessary trial divisions and makes 
    //trial division more feasible for finding large primes

    public static void main(String[] args) 
    {
        long n= 1000000000039L; //this is a large prime number 
        long i = 2L;
        int test = 0;

        while (n > 1)
        {
            while (n % i == 0)
            {
                n /= i;     
            }

            i++;

            if(i*i > n && n > 1) 
            {
                System.out.println(n); //prints n if it's prime
                test = 1;
                break;
            }
        }

        if (test == 0)  
            System.out.println(i-1); //prints n if it's the largest prime factor
    }
于 2014-04-11T13:18:50.080 に答える
3
n = abs(number);
result = 1;
if (n mod 2 == 0) {
 result = 2;
 while (n mod 2 = 0) n /= 2;
}
for(i=3; i<sqrt(n); i+=2) {
 if (n mod i == 0) {
   result = i;
   while (n mod i = 0)  n /= i;
 }
}
return max(n,result)

すべての係数 2 と 3 が削除された場合、n を 6 で割ることはできないため、不要なモジュロ テストがいくつかあります。ここで他のいくつかの回答に示されている i の素数のみを許可できます。

ここで実際にエラトステネスのふるいを絡ませることができます。

  • 最初に までの整数のリストを作成しますsqrt(n)
  • for ループでは、i から new までのすべての倍数をsqrt(n)非素数としてマークし、代わりに while ループを使用します。
  • i をリスト内の次の素数に設定します。

この質問も参照してください。

于 2008-10-14T19:08:35.213 に答える
2

これが迅速な解決策ではないことは承知しています。遅い解決策を理解しやすくすることを願って投稿します。

 public static long largestPrimeFactor(long n) {

        // largest composite factor must be smaller than sqrt
        long sqrt = (long)Math.ceil(Math.sqrt((double)n));

        long largest = -1;

        for(long i = 2; i <= sqrt; i++) {
            if(n % i == 0) {
                long test = largestPrimeFactor(n/i);
                if(test > largest) {
                    largest = test;
                }
            }
        }

        if(largest != -1) {
            return largest;
        }

        // number is prime
        return n;
    } 
于 2012-02-27T22:41:54.750 に答える
1

数値からすべての素因数を削除することによる Python 反復アプローチ

def primef(n):
    if n <= 3:
        return n
    if n % 2 == 0:
        return primef(n/2)
    elif n % 3 ==0:
        return primef(n/3)
    else:
        for i in range(5, int((n)**0.5) + 1, 6):
            #print i
            if n % i == 0:
                return primef(n/i)
            if n % (i + 2) == 0:
                return primef(n/(i+2))
    return n
于 2015-11-09T12:55:37.033 に答える
1

数値を現在の素因数で割り続けるアルゴリズムを使用しています。

Python 3 での私のソリューション:

def PrimeFactor(n):
    m = n
    while n%2==0:
        n = n//2
    if n == 1:         # check if only 2 is largest Prime Factor 
        return 2
    i = 3
    sqrt = int(m**(0.5))  # loop till square root of number
    last = 0              # to store last prime Factor i.e. Largest Prime Factor
    while i <= sqrt :
        while n%i == 0:
            n = n//i       # reduce the number by dividing it by it's Prime Factor
            last = i
        i+=2
    if n> last:            # the remaining number(n) is also Factor of number 
        return n
    else:
        return last
print(PrimeFactor(int(input()))) 

入力:10 出力:5

入力:600851475143 出力:6857

于 2016-09-01T06:08:06.190 に答える
0

C++ で再帰を使用して、数値の最大の素因数を計算します。コードの動作は次のとおりです。

int getLargestPrime(int number) {
    int factor = number; // assumes that the largest prime factor is the number itself
    for (int i = 2; (i*i) <= number; i++) { // iterates to the square root of the number till it finds the first(smallest) factor
        if (number % i == 0) { // checks if the current number(i) is a factor
            factor = max(i, number / i); // stores the larger number among the factors
            break; // breaks the loop on when a factor is found
        }
    }
    if (factor == number) // base case of recursion
        return number;
    return getLargestPrime(factor); // recursively calls itself
}
于 2014-07-12T15:33:08.947 に答える
0

次の C++ アルゴリズムは最適なものではありませんが、10 億未満の数に対して機能し、かなり高速です。

#include <iostream>
using namespace std;

// ------ is_prime ------
// Determines if the integer accepted is prime or not
bool is_prime(int n){
    int i,count=0;
    if(n==1 || n==2)
      return true;
    if(n%2==0)
      return false;
    for(i=1;i<=n;i++){
    if(n%i==0)
        count++;
    }
    if(count==2)
      return true;
    else
      return false;
 }
 // ------ nextPrime -------
 // Finds and returns the next prime number
 int nextPrime(int prime){
     bool a = false;
     while (a == false){
         prime++;
         if (is_prime(prime))
            a = true;
     }
  return prime;
 }
 // ----- M A I N ------
 int main(){

      int value = 13195;
      int prime = 2;
      bool done = false;

      while (done == false){
          if (value%prime == 0){
             value = value/prime;
             if (is_prime(value)){
                 done = true;
             }
          } else {
             prime = nextPrime(prime);
          }
      }
        cout << "Largest prime factor: " << value << endl;
 }
于 2016-06-15T07:56:40.273 に答える
0
#python implementation
import math
n = 600851475143
i = 2
factors=set([])
while i<math.sqrt(n):
   while n%i==0:
       n=n/i
       factors.add(i)
   i+=1
factors.add(n)
largest=max(factors)
print factors
print largest
于 2014-05-31T20:57:01.140 に答える
0

これがc#での私の試みです。最後の出力は、数値の最大の素因数です。私はチェックし、それは動作します。

namespace Problem_Prime
{
  class Program
  {
    static void Main(string[] args)
    {
      /*
       The prime factors of 13195 are 5, 7, 13 and 29.

      What is the largest prime factor of the number 600851475143 ?
       */
      long x = 600851475143;
      long y = 2;
      while (y < x)
      {
        if (x % y == 0)
        {
          // y is a factor of x, but is it prime
          if (IsPrime(y))
          {
            Console.WriteLine(y);
          }
          x /= y;
        }

        y++;

      }
      Console.WriteLine(y);
      Console.ReadLine();
    }
    static bool IsPrime(long number)
    {
      //check for evenness
      if (number % 2 == 0)
      {
        if (number == 2)
        {
          return true;
        }
        return false;
      }
      //don't need to check past the square root
      long max = (long)Math.Sqrt(number);
      for (int i = 3; i <= max; i += 2)
      {
        if ((number % i) == 0)
        {
          return false;
        }
      }
      return true;
    }

  }
}
于 2014-01-20T15:54:25.800 に答える
-1

最初に素数を格納するリストを計算します (例: 2 3 5 7 11 13 ...)。

数値を素因数分解するたびに、Triptych による実装を使用しますが、自然整数ではなく、この素数のリストを繰り返します。

于 2013-11-07T23:09:49.147 に答える
-1

与えられたアルゴリズムのステップ 2 は、それほど効率的なアプローチではないように思えます。それが素数であるという合理的な期待はありません。

また、エラトステネスのふるいを示唆する以前の回答は完全に間違っています。123456789 を因数分解する 2 つのプログラムを作成しました。

1)  Test = 2 
2)  Current = Number to test 
3)  If Current Mod Test = 0 then  
3a)     Current = Current Div Test 
3b)     Largest = Test
3c)     Goto 3. 
4)  Inc(Test) 
5)  If Current < Test goto 4
6)  Return Largest

このバージョンは、Sieve よりも 90 倍高速でした。

問題は、最新のプロセッサでは、操作の種類は操作の数よりもはるかに重要ではなく、上記のアルゴリズムはキャッシュで実行できることは言うまでもありませんが、Sieve は実行できません。Sieve は、すべての合成数を打ち消す多くの操作を使用します。

また、識別された要因を分割することで、テストする必要のあるスペースが減ることにも注意してください。

于 2008-10-28T05:40:45.487 に答える
-3

これはジェネレーターとして提供されているのと同じ function@Triptych で、これも少し単純化されています。

def primes(n):
    d = 2
    while (n > 1):
        while (n%d==0):
            yield d
            n /= d
        d += 1

最大素数は、次を使用して見つけることができます。

n= 373764623
max(primes(n))

および以下を使用して見つかった要因のリスト:

list(primes(n))
于 2013-05-16T18:56:12.553 に答える
-3

これはおそらく常に高速であるとは限りませんが、大きな素約数を見つけることについてより楽観的です。

  1. Nあなたの番号です
  2. プライムならreturn(N)
  3. まで素数を計算するSqrt(N)
  4. 素数を降順で調べます (大きいものが先)
    • もしそうN is divisible by PrimeならReturn(Prime)

編集: ステップ 3 では、エラトステネスのふるいやアトキンスのふるいなど、好きなものを使用できますが、ふるいだけでは最大の素因数を見つけることはできません。(それが、SQLMenace の投稿を公式の回答として選択しない理由です...)

于 2008-08-27T20:45:14.827 に答える
-5

n より小さいすべての可能な素数をどこかに保存し、それらを繰り返し処理して最大の除数を見つけるとよいと思います。prime-numbers.orgから素数を取得できます。

もちろん、あなたの数はそれほど大きくないと思います:)

于 2008-08-22T19:57:15.860 に答える
-6
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include <time.h>

factor(long int n)
{
long int i,j;
while(n>=4)
 {
if(n%2==0) {  n=n/2;   i=2;   }

 else
 { i=3;
j=0;
  while(j==0)
  {
   if(n%i==0)
   {j=1;
   n=n/i;
   }
   i=i+2;
  }
 i-=2;
 }
 }
return i;
 }

 void main()
 { 
  clock_t start = clock();
  long int n,sp;
  clrscr();
  printf("enter value of n");
  scanf("%ld",&n);
  sp=factor(n);
  printf("largest prime factor is %ld",sp);

  printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
  getch();
 }
于 2011-10-08T17:23:59.783 に答える