简体   繁体   English

Java中的素数 - 算法

[英]Prime Numbers in Java - Algorithms

I have started learning to code in Java and decided I would use the Project Euler site to give me little tasks to try and complete with each bit of new coding I learn. 我已经开始学习使用Java编写代码并决定使用Project Euler站点给我一些小任务来尝试完成我学习的每一段新编码。 So I came across Problem 3 : 所以我遇到了问题3

The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143 ? 13195的主要因素是5,7,13和29. 600851475143中最大的素数是多少?

I thought about the problem and researched many different theories about prime numbers and how they can be found via various different calculations (Sieve of Eratosthenes being an example) and the solution I conjured up was to test numbers from 2 --> n and see if they were a prime number, if they were then I would divide the Tn variable (in this case 600851475143) by the newly discovered prime number and see if it was a factor. 我考虑了这个问题并研究了很多关于素数的不同理论以及如何通过各种不同的计算找到它们(以Eratosthenes的筛子为例)我想到的解决方案是测试2 - > n中的数字并查看是否它们是素数,如果它们是那么我将Tn变量(在这种情况下为600851475143)除以新发现的素数并查看它是否是一个因子。 If it was, I would assign it to the variable Hp (Highest Prime number) and at the end of the program I would output Hp to the console to give my result. 如果是,我会将它分配给变量Hp(最高素数),在程序结束时我会将Hp输出到控制台以给出我的结果。

Here is my code: 这是我的代码:

public class Largest_Prime_Factor_NEW_SOLUTION {

    static long Tn = 600851475143L;
    static long Hp = 0;
    static boolean isPrime = false;

    public static void main(String[] args) {

        for (long i=2; i<Tn; i++) {
            System.out.println("TESTING NUMBER " + i);
            for (long k=2; k < i; k++) {
                if (i % k == 0) {
                    System.out.println(i + " IS NOT A PRIME");
                    break;
                } else if (k + 1 == i) {
                    isPrime = true;
                }
            }

            if (isPrime) {
            System.out.println(i + " IS A PRIME");
            if (Tn % i == 0) {
                System.out.println(Tn + " IS DIVISIBLE BY " + i);
                Hp = i;
            } else {
                System.out.println(Tn + " IS NOT DIVISIBLE BY " + i);
            }
            }

            isPrime = false;
        }
        System.out.println("THE HIGHEST PRIME NUMBER OF " + Tn + " IS " + Hp);
    }
}

Now I know that this code is very inefficient and for just starting I have managed to condense it from where I began (there were loops everywhere!) but what I am is asking is, how can I improve this? 现在我知道这段代码非常低效,刚开始我已经设法从我开始的地方压缩它(到处都有循环!)但我要问的是,我该如何改进呢? It's eating away at me because everything I research contradicts what others would do and it's very confusing. 它正在吞噬我,因为我所研究的一切都与别人会做的事情相矛盾,这让人非常困惑。 I have tried the sieve method but i understand that a boolean array can only be an int array and never a long array? 我已经尝试了筛选方法,但我知道布尔数组只能是一个int数组,而不是一个长数组?

I understand that when beginning to code I will be limited to what knowledge I can use, but just out of interest, I am keen to see what the final solution would be. 我明白,在开始编码时,我将仅限于可以使用的知识,但只是出于兴趣,我很想知道最终的解决方案是什么。

What you can do is find the lowest divisor of Tn . 你能做的就是找到Tn的最低除数。 Suppose that is p , find the lowest divisor again for Tn/p and so on. 假设是p ,再次找到Tn/p的最低除数,依此类推。

Now, at every step p is prime[explanation below]. 现在,在每个步骤p都是素数[下面的解释]。 So collect them and they are the prime divisors of Tn . 所以收集他们,他们是Tn的主要除数。

For better time-complexity, you can check for divisors up to upto ceil(sqrt(Tn)) only, instead of Tn-1 . 为了获得更好的时间复杂度,您可以仅检查高达ceil(sqrt(Tn))除数,而不是Tn-1

And when you start checking for prime divisor for Tn , you can start with 2 . 当你开始检查Tn主要除数时,你可以从2开始。 And once you get a prime divisor p don't start again from 2 for Tn/p . 一旦你得到一个素数除数p不要再从2开始为Tn/p Because, Tn/p is also a divisor of Tn and since Tn does not have divisors less than p , Tn/p does not have it too. 因为, Tn/p也是Tn的除数,并且因为Tn没有小于p除数,所以Tn/p也没有。 So start with p again[ p can have multiple power in Tn ]. 所以再次从p开始[ p可以在Tn具有多个功率]。 If p does not divide Tn , move to p+1 . 如果p不除Tn ,则移至p+1

Example : 示例:

Tn = 45 Tn = 45
1. start with 2. 2 does not divides 45. 1.从2开始.2不分45。
2. next test is for 3. 45 is divisible by 3. So 3 is a prime divisor of it. 2.下一个测试是针对3. 45可以被3整除。所以3是它的主要除数。
3. Now check prime divisors from 45/3 = 15, but start with 3. not from 2 again. 3.现在检查45/3 = 15的素数除数,但从3开始,而不是从2开始。 4. Well, 15 is divisible by 3. So start with 15/3 = 5 5. Note for 5, ceil(sqrt(5)) is 3. But 5 is not divisible by 3. But since 4 > ceil(sqrt(5)) and we can say 5 is a prime without any doubt. 4.好吧,15可以被3整除。所以从15/3 = 5开始5.注意5,ceil(sqrt(5))是3.但是5不能被3整除。但是因为4> ceil(sqrt( 5))我们可以毫无疑问地说5是素数。

So the prime divisor of 45 are 3 and 5. 所以45的主要除数是3和5。


Why smallest divisor(except 1) of a number is a prime ? 为什么一个数字的最小除数(1除外)是素数?

Suppose above statement is false. 假设上述陈述是错误的。 Then a number N has a smallest yet composite divisor, say C. 然后数字N具有最小但复合除数,比如说C.

So C|N Now C is composite so, it has divisor less than itself but greater than one. 所以C | N现在C是复合的,它的除数小于自身但大于1。
Say such a divisor of C is P. 说这样的C除数是P.
So P|C , but we have C|N => P|N where 1 < P < C. 所以P | C,但我们有C | N => P | N,其中1 <P <C

This contradicts our assumption that C is the smallest divisor of N, so smallest divisors of a number is always a prime. 这与我们的假设相矛盾,即C是N的最小除数,因此数字的最小除数总是素数。

Thank you for all your help, after reading through the comments and answers I managed to condense the code much further to the following: 感谢您的所有帮助,在阅读完评论和答案之后,我设法将代码进一步压缩到以下内容:

    public class Largest_Prime_Factor_NEW_SOLUTION_2 {

    static long Tn = 600851475143L;

    public static void main(String[] args) {

        for (long i = 2; i < Math.sqrt(Tn); i++) {

            if(Tn % i == 0) {
                Tn = Tn / i;
                i--;
            }   
        }
        System.out.println(Tn);
    }
}

and it works perfect! 它完美无瑕! Thanks again for your help and time to help me understand. 再次感谢您的帮助和时间来帮助我理解。 I understand it was more a mathematical problem than a coding problem, but it helped me understand a few things. 我知道这更像是一个数学问题,而不是编码问题,但它帮助我理解了一些事情。 I'm now off to learn something else :) 我现在要去学习别的东西:)

There are many ways to improve a program like this, but the improvements have to do mostly with mathematics and not programming: 有很多方法可以改进像这样的程序,但改进主要是用数学而不是编程:

  • When looking for factors, check each number, not just primes. 在寻找因素时,请检查每个数字,而不仅仅是素数。 If you find a factor check if it's prime. 如果你找到一个因素检查它是否是素数。 You'll save yourself of many primality checks this way. 你会用这种方式省去许多素数检查。

  • The greatest prime factor of a composite number can be at most the number's square root, so you can stop the iteration earlier. 复合数的最大素数因子最多可以是数字的平方根,因此您可以提前停止迭代。

  • Use a fast primality test instead of doing trial divisions http://en.wikipedia.org/wiki/Primality_test 使用快速素性测试而不是进行试验分割http://en.wikipedia.org/wiki/Primality_test

Then again, this is a one-off. 再说一遍,这是一次性的。 Don't overcomplicate it. 不要过度复杂化。

Since you are doing this as a learning exercise, when you have improved you current program enough, why not try solving the same problem in a different way? 既然你正在做这个学习练习,当你对当前的课程进行了充分的改进时,为什么不尝试以不同的方式解决同样的问题呢? The Fermat Factorization Method finds large factors first. 费马分解方法首先找到大因子。

A simple algorithm for factoring a composite number by trial division goes like this: 通过试验分解对复合数进行分解的简单算法如下:

function factors(n)
    f, fs := 2, []
    while f * f <= n
        while n % f == 0
            fs.append(f)
            n := n / f
        f := f + 1
    if n > 1
        fs.append(n)
    return fs

That algorithm can be improved, and there are better algorithms for factoring large numbers, but it's sufficient for your task. 该算法可以改进,并且有更好的算法来分解大数,但它足以完成您的任务。 When you are ready for more, I modestly recommend the essay Programming with Prime Numbers at my blog, which includes implementations of that algorithm and others in Java. 当你准备好了更多的时候,我在我的博客上谦虚地推荐用Prime数字编写论文 ,其中包括该算法的实现和Java中的其他算法。

This is java version of this : 这是java版的这个

 static boolean isPrime(int n){
    if (n == 2) return true;
    if (n == 3) return true;
    if (n % 2 == 0) return false;
    if (n % 3 == 0) return false;

    int i = 5;
    int w = 2;
    while (i * i <= n) {
        if(n % i == 0)
        return false;

        i += w;
        w = 6 - w;
    }
    return true;
}

As it is described by @Alexandru: It's a variant of the classic O(sqrt(N)) algorithm. 正如@Alexandru所描述的那样:它是经典O(sqrt(N))算法的变体。 It uses the fact that a prime (except 2 and 3) is of form 6k-1 and 6k+1 and looks only at divisors of this form. 它使用了这样一个事实:素数(除了2和3)的形式是6k-1和6k + 1,并且只看这种形式的除数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM