【问题标题】:Brute force method finding prime numbers寻找素数的蛮力方法
【发布时间】:2013-05-24 01:57:07
【问题描述】:

我在编写一个查找 2-50 之间素数的程序时遇到了麻烦。我的程序现在找到“大部分”素数,但包括一些非素数。我知道有很多更有效的方法和策略可以找到素数,但在我转向更有效和更有效的策略之前,我会先尝试所有可能性。现在编写程序的方式,如果它确实找到了一个素数,它会打印多次,而我只希望它打印一次。我的程序在概念上是正确的还是我的理由有缺陷。为什么我的程序主要找到素数但抛出一些非素数?为什么我的程序会多次打印素数?

这是我解决问题的方法。

  1. 创建一个 for 循环来表示 2-50 之间的潜在质数。用变量“i”表示这些潜在的素数。此循环将从 50 开始倒计时。

  2. 由于一个数只有在除了它自己和 1 之外没有其他可整除数时才是素数,我想创建一个内部 for 循环来将 i 除以 2 和 i -1 之间的每个可能的数,看看是否有这些数字均分为 i。用变量 j 表示这些可能的除数。如果在任何时候 j 确实均匀地划分为 i 它不是质数,所以我希望我的内部循环退出。

  3. 如果 i 除以 j 的所有数字,并且没有数字可以均匀地除以 i,那么如果是素数,则该数字要打印该数字。

*

import acm.program.*;
public class PrimeNumber extends ConsoleProgram{
public void run(){

  for (int i =50; i >= 2; i--){
    for (int j= 2; j < i-1; j++){

        if (i % j >= 1){
         println(i);
         }else{
         if (i % j == 0) break;
                }
              } /*end of inner loop */  
           } /* end of for loop */

       } /* end of run method */
     } 

【问题讨论】:

  • 2 和 i -1 这太多了,你可以检查 2 和 sqrt(i) 之间的除法。
  • 要使该算法起作用,对于所有内部循环情况,i%j 必须 >= 1,而不仅仅是一个。正如 cerkiewny 指出的那样,您只需转到 sqrt(i) 即可减少循环迭代。
  • 内循环中的i++一定是错字?
  • 呵呵... cmets 比答案快...击败我。
  • @Radio- 不,不是错字。我希望外循环倒计时,内循环倒计时。因此,例如要测试 50,我想要 50 % 2...3...4.. 一直到 50 % 49。

标签: java math primes


【解决方案1】:

你犯了两个错误。第一个在@Thomas 的评论中解释,第二个在@rolfl 的评论中解释。我在这里更正了它们:

public class PrimeNumber extends ConsoleProgram {
    public void run() {
        for (int i = 50; i >= 2; i--) {
            boolean isPrime = true;
            for (int j = 2; j < i-1; j++) { //increment "j" not "i"
                if (i % j == 0) {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime) System.out.println(i);
        }
    } 
}

注意:我使用此代码验证了解决方案(在您的 IDE 中保存为 PrimeNumber.java):

public class PrimeNumber {
    public static void main (String args[]) {
        for (int i = 50; i >= 2; i--) {
            boolean isPrime = true;
            for (int j = 2; j < i-1; j++) { //increment "j" not "i"
                if (i % j == 0) {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime) System.out.println(i);
        }
    } 
}

编辑:为了您的理解,您的主要问题是这里的逻辑:

for (int j= 2; j < i-1; j++) {
    if (i % j >= 1) {
        println(i);

您只检查了一种可能性后打印i

i = 7 为例。您必须先测试i % jj = 6、5、4、3 和2,然后才能说i 是素数。您不能像您所做的那样只测试i % j 以获得j = 6。为此,您的 println 语句应位于 for 循环之后,而不是嵌套在其中,因此您可以先测试 j 的所有可能值。


编辑2:回应

巧合的是,作业的第一部分是编写一个谓词方法,如果数字是素数,则返回 true,如果不是素数,则使用蛮力策略返回 false。作业的第二部分是找到一种更有效的方法,并将作业的第一部分重新工作以提高效率。我试图用两个 for 循环来解决这个问题,看看我能不能做到。是否可以只使用两个不带标签的 for 循环并继续,因为我的书还没有涉及到?

试试这样的:

public boolean isPrime(int number) {
    for (int i = 2; i < number; i++) {
        if (number % i == 0) {
            return false; //not prime
        }
    }
    return true; //prime
}

【讨论】:

  • 非常感谢。我仍在研究和试验所有答案。你的回答很有道理。
  • 感谢所有帮助。对此,我真的非常感激。您的回答对我帮助很大。
  • 不客气。就第 2 部分而言,您只需要检查数字是否不是偶数,然后取奇数的 mod (%)。
【解决方案2】:

您的第二个循环(内部循环)中有一个错误。

你应该增加 j 而不是 i.... 即内循环应该是

for (int j= 2; j < i-1; j++){

而不是

for (int j= 2; j < i-1; i++){

【讨论】:

    【解决方案3】:

    你正确地观察到如果一个数字i 可以被一个数字j 整除,那么i % j == 0

    但是,每次发现i % j &gt;= 0 的情况时,您都会打印 i ——但这并不意味着i 是素数,因为可能还有其他j 可以是i均分。

    相反,您应该首先检查您所有的j,并且只有当它们都没有给您== 0 时,您才应该考虑i。您可以使用初始为 true 的布尔变量 isPrime,但内部 for 循环在找到 j 后立即设置为 falsei 可以通过该变量平分。

    【讨论】:

    • 这是作业的第二部分。稍后使用谓词方法,该数为真,如果不是,则为假。我还没有解决通过蛮力方法找到素数的第一部分。
    • 这个问题可以只用两个for循环解决还是必须涉及布尔值?
    • 如果你在内循环中使用continue 和外循环的标签,你可以只用两个for循环来完成。这就像使用 GOTO 一样。你确定你的赋值的第二部分暗示你不能在第一部分使用布尔变量吗?
    • 巧合的是,作业的第一部分是编写一个谓词方法,如果数字是素数,则返回true,如果不是素数,则使用蛮力策略返回false。作业的第二部分是找到一种更有效的方法,并将作业的第一部分重新工作以提高效率。我试图用两个 for 循环来解决这个问题,看看我能不能做到。可以只用两个不带标签的 for 循环来完成并继续,因为我的书还没有涉及到吗?
    • 我觉得做不到。但在我看来,这听起来并不像是你应该只使用两个 for 循环而不使用其他任何东西。请注意,布尔变量不是谓词方法。我怀疑您应该编写一个谓词方法boolean isPrime(int n),它基本上可以完成您的内部 for 循环当前所做的事情,但是您可以在该方法中使用布尔变量。然后外部 for 循环可以调用该谓词方法,而不是拥有自己的内部循环。抱歉,我不确定我是否很有帮助。
    【解决方案4】:

    这个 if 语句:

    if (i % j >= 1){
             println(i);
    

    将打印每个未除以 j 数的数字,并且您要打印的数字不是从一个减法中得到除法值不同于 0 的除法值,而是所有减法。

    此外,更快的解决方案是采用潜在素数的布尔数组并像这样循环。

    for ( i = 2; i < sqrt(maxvalue); i ++){
                for(j = 1; j < sqrt(maxval); j++){
                      potentialy_prime[i*j]=false
                }
           }
    for (potentialy_prime){
        if(potentialy_prime[i]==true)
                print(i "is prime")
    }
    

    【讨论】:

      【解决方案5】:

      查看 dydx 对此问题的回答:https://stackoverflow.com/questions/13437162/java-finding-prime-numbers。或者这个问题:Prime number calculation fun 或者这个Getting the prime numbers,等等……

      【讨论】:

        【解决方案6】:

        您的代码存在 3 个问题:

        • 在内循环中,您正在增加i,而不是增加j

        • 您在i % j &gt;= 1 处打印数字,但可能下一个j 将除以i,因此i 不是素数。

        • 您应该在 sqrt(i) 处停止内部循环以避免无用的测试。

        这是代码的更正版本:

        OUTER: for (int i = 50; i >= 2; i--) {
            for (int j = 2; j <= (int) Math.sqrt(i); j++) {
                if (i % j == 0)
                    continue OUTER;
                } /* end of inner loop */
            println(i);
        } /* end of for loop */
        

        【讨论】:

        • @florentBaye 谢谢。仍然有点困惑,但试图弄清楚。谢谢!
        【解决方案7】:

        这段代码应该打印出质数。最初的假设是每个整数 >= 2 都是素数(在布尔数组中为真)。在遍历数组时,如果发现该数字是素数,则通过在布尔数组中将它们设置为 false 来删除该数字的倍数(因为它们不是素数)。最后,布尔数组中为真的数字将仅是素数。

        时间复杂度:O(n log(log n))

        public class PrimesImprovement
        {
            public static void main(String[] args)
            {  
                System.out.println("Printing primes from 1 to 100");
                int i;
                int j;
                //boolean prime;
                boolean[] prime_arr=new boolean[100];
                Arrays.fill(prime_arr,true); // Assumption
                prime_arr[0]=prime_arr[1]=false;  // As 0 and 1 are not prime numbers
                for ( i=2;i<prime_arr.length;i++) 
                {
        
                    if(prime_arr[i])
                    { 
                        for ( j=2;i*j<prime_arr.length;j++) 
                        {
                            prime_arr[i*j]=false;
                        }
                    }
                }
        
                for( i=0; i<prime_arr.length; i++)
                {
                    if(prime_arr[i])
                    {
                        System.out.print(i+" ");
                    }
                }
        
                System.out.println();
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2020-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-29
          • 1970-01-01
          相关资源
          最近更新 更多