简体   繁体   English

Java:找出一个数是否是递归的质数

[英]Java: Find out if a number is prime recursively

I'm writing a function that returns true if a number is prime, and false otherwise我正在编写一个函数,如果数字是素数则返回真,否则返回假

Here is my current code:这是我当前的代码:

    public static boolean checkPrime(int n, int currDivisor){
        if(n < 2){
            return true;
        }
        if(currDivisor == (n/2)){
            return true;
        }
        else if(n % currDivisor == 0 ){
            return false;           
        }
        else{
            return checkPrime(n, currDivisor + 1);
        }
    }

    public static void main(String[] args){
        System.out.println(checkPrime(23352, 2));
    }

It works for a lot of test cases except numbers like "1000000007" where I get an Out of memory error.它适用于许多测试用例,除了像“1000000007”这样的数字,在那里我遇到内存不足错误。 How could I tweak this code to be more efficient space-wise?我如何调整此代码以提高空间效率?

The fundamental problem is that recursion is not the right approach. 根本问题是递归不是正确的方法。 Primality testing is not a recursive problem, and you will always exceed available storage quite quickly for large numbers. 原始性测试不是一个递归问题,对于大量用户,您将始终很快超过可用存储。 I suggest you do some research on the web on the topic of "primality testing". 我建议您在网络上进行有关“原始性测试”的研究。

As to a rule of thumb for deciding if a problem is recursive, I've been doing this so long I'm not sure I can express what has become completely intuitive, so I'll let someone else do it. 关于确定问题是否递归的经验法则,我已经做了很久了,我不确定我能否表达出已经完全直观的内容,所以我会让别人去做。

However, it's worth pointing out that some problems that are mathematically recursive have computational solutions where iteration is far, far better than naive recursion. 但是,值得指出的是,一些数学上递归的问题具有计算解决方案,其中迭代远比幼稚的递归好得多。 The prime (hah!) example of that is Fibonacci numbers. 素数(哈!)的例子是斐波那契数。 For large n the naively recursive solution eats memory and performs redundant calculations, while the iterative solution is faster and better all around. 对于较大的n,天真的递归解决方案会占用内存并执行冗余计算,而迭代解决方案在整个过程中都更快,更好。

The first problem I see is that your program is it's buggy. 我看到的第一个问题是您的程序是越野车。 It seems to think that 0, 1, & 4 are primes and that 3 isn't. 似乎认为0、1,&4是质数,而3不是。 The second problem I see is that it's wasting stack frames not properly dealing with simple cases before recursing. 我看到的第二个问题是,它浪费了堆栈帧,在递归之前没有正确处理简单的情况。 Here's my rework of your code: 这是我对您的代码的重做:

public static boolean checkPrime(int n) {
    return checkPrime1(n, 3);
}

public static boolean checkPrime1(int n, int currDivisor) {
    if (n < 2) {
        return false;
    }

    if (n % 2 == 0) {
        return (n == 2);
    }

    if (currDivisor * currDivisor > n) {
        return true;
    }

    if (n % currDivisor == 0) {
        return false;
    }

    return checkPrime1(n, currDivisor + 2);
}

As far as handling: 至于处理:

System.out.println(checkPrime(1000000007));

You'll still get an java.lang.StackOverflowError but that's not the end of the story. 您仍然会遇到java.lang.StackOverflowError但这还不是故事的结尾。 Most languages make decisions of how much memory to allocate to specific purposes. 大多数语言都会决定要分配给特定用途的内存量。 It's the rare language like Perl that will reallocate memory to whatever resource is demanding it most and not make assumptions about how a program should behave. 像Perl这样的稀有语言会将内存重新分配给最需要它的资源,而不会对程序的行为做任何假设。

You can change the amount of memory allocated to Java's stack -- calling java with the -Xss2m argument allocates sufficient extra stack to let you test 1000000007 ( true , by the way.) 您可以更改分配给Java堆栈的内存量-使用-Xss2m参数调用java分配足够的额外堆栈,以供您测试1000000007(顺便说一下,是true )。

If you change the three int declarations above to long , you'll be able to test numbers like 2547487897L or larger as long as you expand the stack ( -Xss4m in this case.) 如果你改变了三种int上述报关单long ,你就可以像测试数字2547487897L只要您展开堆栈或更大( -Xss4m在这种情况下)。

I'm not saying that this is a good problem for recursion, it isn't. 我并不是说这是递归的好问题,不是。 But if you're going to use recursion, use it wisely. 但是,如果您要使用递归,请明智地使用它。 It's poor recursion that's gives recursion a bad name. 不好的递归使递归变得不好用。 There are inefficient recursive Fibonnaci algorithms (usually doubly recursive) and efficient (singly recursive) ones. 有低效的递归Fibonnaci算法(通常是双递归)和高效的(单递归)算法。 Recursive code usually works best with recursive data. 递归代码通常最适合递归数据。

Some languages, not yet Java consistently, can optimize the above code as a tail recursion and make it effectively iterative performance. 某些语言(不是Java一致的语言)可以将上述代码作为尾部递归进行优化,并使其具有有效的迭代性能。

    /*by mostafa asem aljbali*/
    static boolean isPrime(int num, int i){

        if (num <= 2){
            return (num == 2) ? true : false;
        }
        if (num % i == 0){
            return false;
        }
        if (i * i > num){
            return true;
        }

        return isPrime(num , (i + 1));
    }
 public static void main(String[] args){
    System.out.println("Is Prime: "+ isPrime(7, 2));
}

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

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