【问题标题】:Java - Increasing performance of a simple prime number validatorJava - 提高简单素数验证器的性能
【发布时间】:2018-07-26 20:43:53
【问题描述】:

我正在学习 Java 课程,刚刚完成了一项作业,但我的脑海中留下了一个问题。我还没有时间问我的教授,无论如何这与我们正在做的事情有点偏离主题。

基本上,我们有一个程序可以验证用户输入的整数是否为素数。如果它不是素数,它会计算小于输入的最接近的素数。例如:

Enter an integer: 4
4 is not a prime number. The closest prime number is 3.

如果输入不是素数,则程序使用循环按预期工作。这是我的代码:

public static void main(String[] args) {

    Scanner input = new Scanner(System.in);
    int number;

    System.out.print("Please enter a positive, non-zero integer: ");
    number = input.nextInt();
    input.close();

    if (isValid(number) == true) {
        if(isPrime(number) == true) {
            System.out.printf("%d is a prime number.", number);
        } else {
            switch(number) {
                case 1: 
                    System.out.print("1 is not a prime number. \n");
                    System.out.print("We cannot find the nearest prime.");
                    break;
                default:
                    System.out.printf("%d is not a prime number.", number);
                    System.out.printf("\nThe nearest prime number is %d.", getNearestPrime(number));
                }
            }
        } else {
        System.out.print("Invalid input. Please run again.");
        System.exit(1);
    }   
}

public static boolean isValid(int number) {

    if (number > 0) {
        return true;
    } else {
        return false;
    }
}

public static boolean isPrime(int number) {

    int i;
    if(number == 1) {
        return false;
    } else {
        for(i = 2; i < number; i++) {
            if(number%i == 0) {
                return false;
            }
        }
        return true;
    }
}

public static int getNearestPrime(int number) {

    do {
        number--;
    } while (isPrime(number) == false);

    return number;
}

请务必注意,我们需要创建下面列出的三种方法 main.

我的问题是:在这种情况下计算较大的整数时,有没有办法提高性能?

如果我输入 2,147,483,647,程序需要大约 10 秒来识别它是素数。如果我输入 2,147,483,646,找到最接近的素数所需的时间大致相同。

我完全理解为什么会发生这种情况,但似乎我使用过的任何高级 Java 应用程序都可以比我的简单程序更快地处理更复杂的事情。

我真的很好奇有经验的程序员如何处理这样的事情。谢谢!

【问题讨论】:

  • 有几种方法可以显着提高此代码的性能。其中一些非常简单,例如基于prime number sieves 的方法。不幸的是,所提出的问题对于 Stack Overflow 来说太宽泛了,但是您可以考虑在 Code Review 中提问。不过,请务必先检查their criteria
  • @JohnBollinger 有趣,感谢您的回复。我只是查找了素数筛,如果我错了,请纠正我,但这不需要其他方法吗?我可能应该补充说,我们只被允许使用 isValid()、isPrime() 和 getNearestPrime()——仅此而已。也感谢您指点我进行代码审查!
  • 不,没有什么特别的理由需要额外的方法,尽管限制不实现任何额外的方法是非常人为的。
  • 如果您(或其他访问者)曾经处理过更大的整数,您可能会对Primality testjava.math.BigInteger.isProbablePrime(int) 的维基百科文章感兴趣。
  • 提高性能的最大单一变化,也很容易实现,是@JohnBollinger 已经提到的:只循环到方法 isPrime 中正在测试的数字的平方根()。之后的任何额外循环都是没有意义的。

标签: java math calculation


【解决方案1】:

你可以改变几个简单的事情:

1) 素数永远不会是偶数,所以一旦你检查了一个数是否能被 2 整除,你就不需要检查它是否能被任何其他偶数整除。所以你可以稍微简化你的循环。 (只需添加一个if 语句来检查号码是否为2,然后从三点开始i

2) 你只需要循环直到数字的平方根。

  int i;
  if(number == 1) {
      return false;
  }
  if(number == 2) {
     return true; //2 is a prime number
  } 
  if (number % 2 == 0) {
     return false;
  }
  for(i = 3; i* i <= number; i+=2) {
      if(number%i == 0) {
          return false;
      }
  }
  return true;

【讨论】:

  • 不,不,不。不要将浮点数学带入其中,也不要为此引入不必要的方法调用。 i * i &lt;= number 会很好。
  • @JohnBollinger 那将是一个更好的方法,不是吗.. 感谢您的出色建议!
  • @GBlodgett 离题,但为什么代码注释声明“2 技术上是一个素数”?它和其他任何素数一样都是素数。
【解决方案2】:

需要注意的一件事是,在算法方面,可以使用更高效的算法。 See this answer for details

关于实现,如果您想提高性能,您可以使用一些技巧,例如缓存最近的结果。 一种更有效但可能超出课程范围的方法是使用预先计算的素数列表。 您可以在 Internet 上找到一个,或者您可以运行一次程序来预先计算它们直到给定的点。

请注意,这种方法会为了速度而牺牲一些内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-20
    • 2018-02-09
    • 2016-12-06
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    相关资源
    最近更新 更多