2010-11-25 2 views
2

Я работаю над простой программой факторизации, реализованной на Java. Цель состоит в том, чтобы найти самый большой первичный коэффициент 600851475143 (Project Euler problem 3). Я думаю, что у меня больше всего сделано, но я получаю несколько ошибок. Также моя логика отключена, в частности метод, который я настроил для проверки, является ли число простым.Программа Prime Factorization в Java

public class PrimeFactor { 

    public static void main(String[] args) { 
     int count = 0; 
     for (int i = 0; i < Math.sqrt(600851475143L); i++) { 
      if (Prime(i) && i % Math.sqrt(600851475143L) == 0) { 
       count = i; 
       System.out.println(count); 
      } 
     } 
    } 

    public static boolean Prime(int n) { 
     boolean isPrime = false; 
     // A number is prime iff it is divisible by 1 and itself only 
     if (n % n == 0 && n % 1 == 0) { 
      isPrime = true; 
     } 
     return isPrime; 
    } 
} 

Редактировать

public class PrimeFactor { 

    public static void main(String[] args) { 
     for (int i = 2; i <= 600851475143L; i++) { 
      if (isPrime(i) == true) { 
       System.out.println(i); 
      } 
     } 
    } 

    public static boolean isPrime(int number) { 
     if (number == 1) return false; 
     if (number == 2) return true; 
     if (number % 2 == 0) return false; 
     for (int i = 3; i <= number; i++) { 
      if (number % i == 0) return false; 
     } 
     return true; 
    } 
} 
+0

Какие ошибки вы получаете? и в каких строках вы получаете ошибки? – 2010-11-25 02:56:35

+5

Ваш Prime метод всегда возвращает true, потому что `n% n == 0 && n% 1 == 0` для всех` n`. То есть все числа делятся сами по себе и 1. Вам не хватает «единственной» части определения. – 2010-11-25 02:59:37

+0

К сожалению, вы даже не близко. Ваш алгоритм примитивности не работает, потому что все числа делятся сами по себе и нуль - это просто, что простые числа не делятся ничем другим, и вам нужно выполнить проверку для этого. Решетке Erasthones требуется 600 ГБ оперативной памяти для работы до значения в диапазоне 600B, поэтому рекурсивная простая факторизация является единственной практической стратегией и с большим проблемным пространством потребуются часы или дни. Это основа всего современного шифрования: простая факторизация выше размера ОЗУ очень медленная. – 2010-11-25 03:02:20

ответ

22

Почему это так сложно? Вы не нужно сделайте все как isPrime(). Разделите его наименьший делитель (prime) и сделайте цикл из этого числа. Вот мой простой код:

public class PrimeFactor { 

    public static int largestPrimeFactor(long number) { 
     int i; 

     for (i = 2; i <= number; i++) { 
      if (number % i == 0) { 
       number /= i; 
       i--; 
      } 
     } 

     return i; 
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     System.out.println(largestPrimeFactor(13195)); 
     System.out.println(largestPrimeFactor(600851475143L)); 
    } 
} 
2

Вы хотите перебрать от 2 -> п-1 и убедитесь, что п% = 0. Это самый наивный способ проверить для простоты!. Как объяснялось выше, это очень медленно, если число велико.

1

Я думаю, вы смущены, потому что нет оператора iff [if-and-only-if].

Переход к квадратному корню из целого числа является хорошим ярлыком. Остается только проверить, равномерно ли число в этом цикле делится. Это просто [большое число]% i == 0. Нет причин для вашей функции Prime.

Поскольку вы ищете самый большой делитель, другой трюк должен начинаться с наивысшего целого числа меньше квадратного корня и идти i--.

Как и другие, в конечном счете это жестоко медленно.

2

Чтобы найти факторы, вы хотите что-то вроде:

long limit = sqrt(number); 
for (long i=3; i<limit; i+=2) 
    if (number % i == 0) 
     print "factor = " , i; 

В этом случае факторы, все достаточно малы (< 7000), что найти их следует принимать также под второй, даже наивным такой код , Также обратите внимание, что это конкретное число имеет другие, меньшие, простые факторы. Для поиска грубой силы, как это, вы можете сэкономить небольшую работу, разделив меньшие факторы по мере их нахождения, а затем сделайте основную факторизацию меньшего числа, которое получится. Преимуществом этого является то, что он дает только основные факторы. В противном случае вы также получите составные коэффициенты (например, это число имеет четыре основных фактора, поэтому первый метод будет печатать не только основные факторы, но и продукты различных комбинаций этих простых факторов).

Если вы хотите немного оптимизировать это, вы можете использовать сито Eratosthenes, чтобы найти простые числа до квадратного корня, а затем только попытаться делить на простые числа. В этом случае квадратный корень равен ~ 775'000, и вам нужно всего один бит на номер, чтобы указать, является ли он простым. Вы также (обычно) хотите хранить нечетные числа (так как вы сразу же знаете, что все четные числа, но два являются составными), поэтому вам нужно ~ 775'000/2 бит = ~ 47 килобайт.

В этом случае у этого есть небольшая реальная выплата, хотя - даже совершенно наивный алгоритм будет давать результаты мгновенно.

10

Редактировать: Я надеюсь, что это не звучит невероятно снисходительно, как ответ. Я просто хотел проиллюстрировать это с точки зрения компьютера, вы должны проверить все возможные числа, которые могут быть факторами X, чтобы убедиться, что это просто. Компьютеры не знают, что это композит, просто глядя на него, поэтому вам нужно итерации

Пример: Является ли X простым числом?

Для случая, когда X = 67:

Как вы это проверить?

I divide it by 2... it has a remainder of 1 (this also tells us that 67 is an odd number) 
I divide it by 3... it has a remainder of 1 
I divide it by 4... it has a remainder of 3 
I divide it by 5... it has a remainder of 2 
I divide it by 6... it has a remainder of 1 

Фактически, вы получите только остаток от 0, если число не является простым.

Вам нужно проверить каждое число меньше X, чтобы убедиться, что оно простое? Неа. Не больше, благодаря математике (!)

Давайте посмотрим на меньшем количестве, как 16

16 не является простым.

Почему? потому что

2*8 = 16 
4*4 = 16 

Таким образом, 16 равномерно делится более чем на 1 и на себя. (Хотя «1» технически не является простым числом, но это технические детали, и я отвлекся)

Таким образом, мы разделим 16 на 1 ... конечно это работает, это работает для каждого номера

Divide 16 by 2... we get a remainder of 0 (8*2) 
Divide 16 by 3... we get a remainder of 1 
Divide 16 by 4... we get a remainder of 0 (4*4) 
Divide 16 by 5... we get a remainder of 1 
Divide 16 by 6... we get a remainder of 4 
Divide 16 by 7... we get a remainder of 2 
Divide 16 by 8... we get a remainder of 0 (8*2) 

Нам действительно нужен только один остаток от 0, чтобы сказать, что он композитный (противоположность «prime» является «составным»).

Проверяется 16 делится на 2 это то же самое, как проверка, если он делится на 8, потому что 2 и 8 умножить, чтобы дать вам 16.

Нам нужно только проверить часть спектра (от 2 до квадратного корня X), потому что наибольшее число, которое мы можем умножить, это sqrt (X), иначе мы используем меньшие числа, чтобы получить избыточные ответы.

Есть 17 премьер?

17 % 2 = 1 
17 % 3 = 2 
17 % 4 = 1 <--| approximately the square root of 17 [4.123...] 
17 % 5 = 2 <--| 
17 % 6 = 5 
17 % 7 = 3 

Результаты после SQRT (X), как 17 % 7 и так далее, являются избыточными, поскольку они обязательно должны умножаться с чем-то меньшим, чем SQRT (X) с получением X.

То есть,

а * в = Х

если а и в оба больше, чем SQRT (X), а затем

A * B даст число, которое больше, чем X.

Таким образом, один из A или B должен быть меньше, чем sqrt (X), и избыточно проверять оба этих значения, поскольку вам нужно только знать, разделяет ли один из них X равномерно (четное деление дает вам другое значение в качестве ответа)

Я надеюсь, что это поможет.

Редактирование: Есть более сложные методы проверки примитивности, и Java имеет встроенное «это число, вероятно, простое» или «это число, безусловно, сложный» метод в BigInteger class, как я недавно узнал через другой ответ SO:]

4

Необходимо провести исследование алгоритмов факторизации большое номера; this wikipedia page выглядит как хорошее место для начала. В первом абзаце говорится:

Когда число очень велико, не эффективный алгоритм факторизации целое не является общеизвестным ...

но это Перечислим ряд специальных алгоритмов и общего назначения , Вам нужно выбрать тот, который будет работать достаточно хорошо, чтобы иметь дело с 12 десятичными цифрами. Эти числа слишком велики для наивного подхода к работе, но достаточно малы, чтобы (например) работала бы на основе перечисления простых чисел, начиная с 2. (Подсказка - начните с сита Эрастонов)

4

Здесь очень элегантный ответ - который использует грубую силу (не какой-то фантазии алгоритм), но умным способом - за счет снижения предела, как мы находим простые числа и разделите композит от этих простых чисел. ..

Он также печатает только простые числа - и просто простые числа, и если один штрих больше, чем один раз в продукте, он будет печатать его столько раз, сколько это простое в продукте.

public class Factorization { 
    public static void main(String[] args) { 
    long composite = 600851475143L; 
    int limit = (int)Math.sqrt(composite)+1; 
    for (int i=3; i<limit; i+=2) 
    { 
     if (composite%i==0) 
     { 
      System.out.println(i); 
      composite = composite/i; 
      limit = (int)Math.sqrt(composite)+1; 
      i-=2; //this is so it could check same prime again 
     } 
    } 
    System.out.println(composite); 
    } 
} 
1
private static boolean isPrime(int k) throws IllegalArgumentException 
    { 
     int j; 

     if (k < 2) throw new IllegalArgumentException("All prime numbers are greater than 1."); 
     else { 
      for (j = 2; j < k; j++) { 
       if (k % j == 0) return false; 
      } 
     } 

     return true; 
    } 

    public static void primeFactorsOf(int n) { 
     boolean found = false; 

     if (isPrime(n) == true) System.out.print(n + " "); 
     else { 
      int i = 2; 
      while (found == false) { 
       if ((n % i == 0) && (isPrime(i))) { 
        System.out.print(i + ", "); 
        found = true; 
       } else i++; 
      } 
      primeFactorsOf(n/i); 
     } 
    } 
0

Для тех ответов, которые используют метод isPrime(int) : boolean, есть более быстрый алгоритм, чем та, что ранее реализованного (что-то вроде)

private static boolean isPrime(long n) { //when n >= 2 
    for (int k = 2; k < n; k++) 
     if (n % k == 0) return false; 

    return true; 
} 

и именно это:

private static boolean isPrime(long n) { //when n >= 2 
    if (n == 2 || n == 3) return true; 

    if (n % 2 == 0 || n % 3 == 0) return false; 

    for (int k = 1; k <= (Math.floor(Math.sqrt(n)) + 1)/6; k++) 
     if (n % (6 * k + 1) == 0 || n % (6 * k - 1) == 0) return false; 

    return true; 
} 

Я сделал этот алгоритм, используя два факта:

  1. Нам нужно всего лишь проверить на n % k == 0 до k <= Math.sqrt(n). Это верно, потому что для чего-то более высокого, факторы просто «переворачиваются», например. рассмотрите случай n = 15, где 3 * 5 = 5 * 3, и 5>Math.sqrt(15). Нет необходимости в этом перекрытии проверки как 15 % 3 == 0, так и 15 % 5 == 0, когда мы могли бы просто проверить одно из этих выражений.
  2. Все простые числа (за исключением 2 и 3) могут быть выражены в виде (6 * k) + 1 или (6 * k) - 1, потому что любое положительное целое число может быть выражено в виде (6 * k) + n, где n = -1, 0, 1, 2, 3, or 4 и k представляет собой целое число <= 0, и случаи, когда n = 0, 2, 3, and 4 являются все приводимым ,

Поэтому n является простым, если оно не делится на 2, 3, или некоторое целое число от формы 6k ± 1 <= Math.sqrt(n). Следовательно, приведенный выше алгоритм.

-

Wikipedia article on testing for primality

-

Edit: Мысль я мог бы также опубликовать мое полное решение (* я не использовал isPrime(), и мое решение практически идентично началу ответа , но я думал, что я должен ответить на актуальный вопрос):

public class Euler3 { 

    public static void main(String[] args) { 
     long[] nums = {13195, 600851475143L}; 

     for (num : nums) 
      System.out.println("Largest prime factor of " + num + ": " + lpf(num)); 

    } 

    private static lpf(long n) { 
     long largestPrimeFactor = 1; 
     long maxPossibleFactor = n/2; 

     for (long i = 2; i <= maxPossibleFactor; i++) 
      if (n % i == 0) { 
       n /= i; 
       largestPrimeFactor = i; 

       i--; 
      } 

      return largestPrimeFactor; 

    } 

} 
0

Чтобы найти все простые множители

import java.math.BigInteger; 
import java.util.Scanner; 


public class BigIntegerTest { 


    public static void main(String[] args) { 


      BigInteger myBigInteger = new BigInteger("65328734260653234260");//653234254 
      BigInteger originalBigInteger; 
      BigInteger oneAddedOriginalBigInteger; 
      originalBigInteger=myBigInteger; 
      oneAddedOriginalBigInteger=originalBigInteger.add(BigInteger.ONE); 
      BigInteger index; 
      BigInteger countBig; 


      for (index=new BigInteger("2"); index.compareTo(myBigInteger.add(BigInteger.ONE)) <0; index = index.add(BigInteger.ONE)){ 

       countBig=BigInteger.ZERO; 
       while(myBigInteger.remainder(index) == BigInteger.ZERO){ 
        myBigInteger=myBigInteger.divide(index); 
        countBig=countBig.add(BigInteger.ONE); 
       } 

       if(countBig.equals(BigInteger.ZERO)) continue; 
       System.out.println(index+ "**" + countBig); 

      } 
      System.out.println("Program is ended!"); 
    } 
} 
0

У меня очень похожая проблема для моего класса программирования. В моем классе ему приходилось вычислять введенное число. Я использовал решение, очень похожее на Стиджака. Я отредактировал мой код, чтобы сделать номер из этой проблемы, вместо использования ввода.

Некоторые отличия от кода Stijak являются следующие:

Я считал даже цифры в моем коде.

Мой код печатает только самый большой простой коэффициент, а не все факторы.

Я не пересчитываю коэффициентLimit до тех пор, пока я не разделил все экземпляры текущего фактора.

У меня были все переменные, объявленные как долго, потому что я хотел гибко использовать его для очень больших значений числа. Я считаю, что худшим сценарием было очень большое простое число, например 9223372036854775783, или очень большое число с квадратным корнем с простым числом, например 9223371994482243049. Чем больше факторов, тем быстрее работает алгоритм. Поэтому лучшим сценарием будет число, например, 4611686018427387904 (2^62) или 6917529027641081856 (3 * 2^61), так как оба имеют 62 фактора.

public class LargestPrimeFactor 
{ 
    public static void main (String[] args){ 
     long number=600851475143L, factoredNumber=number, factor, factorLimit, maxPrimeFactor; 
     while(factoredNumber%2==0) 
      factoredNumber/=2; 
     factorLimit=(long)Math.sqrt(factoredNumber); 
     for(factor=3;factor<=factorLimit;factor+=2){ 
      if(factoredNumber%factor==0){ 
       do factoredNumber/=factor; 
       while(factoredNumber%factor==0); 
       factorLimit=(long)Math.sqrt(factoredNumber); 
      } 
     } 
     if(factoredNumber==1) 
      if(factor==3) 
       maxPrimeFactor=2; 
      else 
       maxPrimeFactor=factor-2; 
     else 
      maxPrimeFactor=factoredNumber; 
     if(maxPrimeFactor==number) 
      System.out.println("Number is prime."); 
     else 
      System.out.println("The largest prime factor is "+maxPrimeFactor); 
    } 
} 
0
public class Prime 
{ 
int i; 

public Prime() 
{ 
    i = 2; 
} 

public boolean isPrime(int test) 
{ 
    int k; 

    if(test < 2) 
     return false; 
    else if(test == 2) 
     return true; 
    else if((test > 2) && (test % 2 == 0)) 
     return false; 
    else 
    { 
     for(k = 3; k < (test/2); k += 2) 
     { 
      if(test % k == 0) 
       return false; 
     } 

    } 

    return true; 

} 

public void primeFactors(int factorize) 
{ 
    if(isPrime(factorize)) 
    { 
     System.out.println(factorize); 
     i = 2; 
    } 
    else 
    { 
     if(isPrime(i) && (factorize % i == 0)) 
     { 
      System.out.print(i+", "); 
      primeFactors(factorize/i); 
     } 
     else 
     { 
      i++; 
      primeFactors(factorize); 
     } 
    } 

    public static void main(String[ ] args) 
    { 
     Prime p = new Prime(); 

     p.primeFactors(649); 
     p.primeFactors(144); 
     p.primeFactors(1001); 
    } 
}