Java中的Prime分解程序

时间:2010-11-25 02:55:09

标签: java math primes

我正在研究用Java实现的素数分解程序。 目标是找到最大的素数因子600851475143(Project Euler problem 3)。 我想我已经完成了大部分工作,但是我遇到了一些错误。 此外,我的逻辑似乎已关闭,特别是我设置的方法,用于检查数字是否为素数。

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;
    }
}

12 个答案:

答案 0 :(得分:22)

为什么要这么复杂?您不需要执行 isPrime()之类的操作。除以它的最小除数(素数)并从这个素数做循环。这是我的简单代码:

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));
    }
}

答案 1 :(得分: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的余数来告诉我们它的复合(与“素数”相反的是“复合”)。

检查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.

即,

A * B = X

如果A和B都大于sqrt(X)那么

A * B将产生一个大于X的数字。

因此,A或B中的一个必须小于sqrt(X),并且检查这两个值是多余的,因为您只需要知道其中一个是否均匀地划分X(偶数除法给出了其他价值作为答案)

我希望有所帮助。

编辑:有更复杂的检查素数的方法,而且我最近通过另一个SO学习了BigInteger class中内置的“这个数字可能是素数”或“这个数字肯定是复合的”方法回答:]

答案 2 :(得分:4)

您需要对用于分解数字的算法进行一些研究; this wikipedia page看起来像个好地方。在第一段中,它指出:

  

当数字非常大时,没有公认的有效整数分解算法......

但它确实列出了许多特殊和通用算法。你需要选择一个能够很好地处理12个十进制数字的数字。这些数字对于最天真的工作方法而言太大了,但足够小(例如)基于枚举从2开始的素数的方法可行。 (提示 - 从Erasthones的筛子开始)

答案 3 :(得分: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);
    }
}

答案 4 :(得分:2)

您希望从2开始迭代 - > n-1并确保n%i!= 0.这是检查素性的最天真的方法。如上所述,如果数量很大,这非常慢。

答案 5 :(得分: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千字节。

在这种情况下,这几乎没有真正的回报 - 即使是一个完全天真的算法也会立即产生结果。

答案 6 :(得分:1)

我认为你很困惑,因为没有iff [if-and-only-if]运算符。

转到相关整数的平方根是一个很好的捷径。剩下的就是检查该循环中的数字是否均匀分配。这只是[大数字]%i == 0.你的Prime功能没有理由。

由于你正在寻找最大的除数,另一个技巧是从小于平方根的最高整数开始,然后去i - 。

就像其他人所说,最终,这是非常缓慢的。

答案 7 :(得分: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);
        }
    }

答案 8 :(得分: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)。这是正确的,因为对于任何更高的因素,仅仅是&#34;翻转&#34;恩。考虑案例n = 15,其中3 * 5 = 5 * 35&gt; Math.sqrt(15)。当我们只检查其中一个表达式时,不需要检查15 % 3 == 015 % 5 == 0这种重叠。
  2. 所有素数(23除外)均可以(6 * k) + 1(6 * k) - 1的形式表示,因为任何正整数都可以{{1}的形式表示其中(6 * k) + nn = -1, 0, 1, 2, 3, or 4是一个整数k,以及<= 0都可以归还的情况。
  3. 因此,n = 0, 2, 3, and 4如果不能被n23形式的某个整数整除,则为素数。因此上面的算法。

    -

    Wikipedia article on testing for primality

    -

    编辑:我想我也可以发布我的完整解决方案(*我没有使用6k ± 1 <= Math.sqrt(n),我的解决方案与最佳答案几乎相同,但我认为我应该回答实际问题):

    isPrime()

答案 9 :(得分: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!");
     }
}

答案 10 :(得分:0)

我的编程课遇到了一个非常类似的问题。在我的课堂上,它必须计算输入的数字。我使用的解决方案非常类似于Stijak。我编辑了我的代码来处理这个问题的数字,而不是使用输入。

与Stijak代码的一些区别是:

我在代码中考虑了偶数。

我的代码只打印最大的素数因子,而不是所有因素。

我不会重新计算factorLimit,直到我将当前因子的所有实例都分开。

我声明了所有变量,因为我希望能够灵活地将它用于非常大的数字值。我发现最坏的情况是一个非常大的素数,如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);
    }
}

答案 11 :(得分: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 );
   }
}