找到一个非常大的数字

时间:2014-02-02 01:25:10

标签: java

所以,我试图找到最大的素数因子600851475143.我有一个简单的方法,找到目前最大的一个:

private static void findPrimeFactors(long num) {
        ArrayList<Long> list = new ArrayList<Long>();
        for (long i = 1; i <= num; i++) {
            int lol = 0;
            for (int a = 1; a < i; a++) {
                if (i % a == 0) {
                    lol++;
                }
            }
            if (lol < 2) {
                if (!list.isEmpty())
                    list.remove(list.size() - 1);
                list.add(i);
            }
        }
        System.out.println(list.get(list.size() - 1));
    }

请原谅我糟糕的编程,我还在学习。我认为从列表中删除了很多条目会减少计算时间,所以我删除了最后一个条目,除非它是最后一个条目。我可以使用100L输出以下内容:

97
Done in 1.0 milliseconds (0.001 seconds) (0.0625622 nano seconds)

和20,000:

19997
Done in 1774.0 milliseconds (1.774 seconds) (177.3702774 nano seconds)

正如您所看到的,在更大的数字中找到它需要更长的时间。现在我应该在600851475143找到我想要的号码,所以我可以说它需要一段时间才能完成。我想知道他们是否有更快的计算方法?这是我的所有代码:

import java.util.ArrayList;


public class Main {

    public static void main(String[] args) {
        try {
        long num = 600851475143L;
        long time = System.currentTimeMillis();
        long timeNano = System.nanoTime();

        findPrimeFactors(20000);

        double finishTime = System.currentTimeMillis() - time;
        double finishTimeNano = System.nanoTime() - timeNano;
        System.out.println("Done in " + finishTime + " milliseconds (" + ((finishTime) / 1000) + " seconds)" + " (" + finishTimeNano / 10000000 + " nano seconds)");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void findPrimeFactors(long num) {
        ArrayList<Long> list = new ArrayList<Long>();
        for (long i = 1; i <= num; i++) {
            int lol = 0;
            for (int a = 1; a < i; a++) {
                if (i % a == 0) {
                    lol++;
                }
            }
            if (lol < 2) {
                if (!list.isEmpty())
                    list.remove(list.size() - 1);
                list.add(i);
            }
        }
        System.out.println(list.get(list.size() - 1));
    }
}

如何提高速度的任何提示都值得赞赏!你们中的许多人可能知道我是通过Project Euler做的。

4 个答案:

答案 0 :(得分:1)

你必须要理解的第一件事是,你的任务基本上是“找到一个大数字的一个主要因素”。如果您知道如何操作,可以将您的大数除以找到的因子并重复。

...但我很遗憾地告诉你,没有已知算法在多项式时间内找到laaaaarge数的素因子。实际上,这是许多密码系统(例如着名的RSA)的基础。

然而,现在可以很快地分解大小为600851475143的数字。有很多算法可以做到 - 但你必须学习一些数学来理解它们。

只是这个号码,我可以告诉你600851475143 = 71 * 839 * 1471 * 6857。

答案 1 :(得分:0)

如果您正在寻找最大的因素,您可以从最大的数字开始。这样的事情(未经测试的代码):

private static void findPrimeFactors(long num) {
  long i;
  boolean candidate;
  for (i=num; i>1; i--){
    // i is candidate to be prime factor
    candidate=true;
    for (int a=2; candidate && a<i; a++){
      if (i % a == 0) candidate=false; // i is not prime.
    }
    if (candidate) break;
  }

  System.out.println(i);

}

如果你有一个素数列表而不是测试从2到i的每个数字,你可以实现更好的性能,你只测试内在的素数小于i。

import java.util.*;

public class PrimeFinder {

  private static List<Long> finder (Long max){
    List<Long> list=new ArrayList<Long>();
    Long maxPrime=2L;
    Long i;
    boolean candidate=true;
    for (i=2L;i<max;i++){
      candidate=true;
      for (Long prime:list){
        if (i % prime==0) {candidate=false;break;}
      }
      if (candidate){
        list.add(i);
        System.out.println(i+" "+list.size());
        maxPrime=i;
      }
    }

    System.out.println(maxPrime);
    return list;

  }

  public static void main(String[] argv){
    finder(600851475143L);
  }
}

最好的算法似乎是atkin的筛选。在这里能找到它: Sieve of Atkin - Explanation and Java example

答案 2 :(得分:0)

提高速度的提示:

  • 您正在尝试随时修改ArrayList,每次执行此操作时,阵列列表将花费O(n)时间。如果你真的需要修改列表,请查看使用链表。
  • 您不需要测试所有数字,只需要测试素数。

答案 3 :(得分:0)

您需要更好的算法。这是一个简单的试验部门实施:

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

我将留给您使用适当的数据类型将该伪代码转换为您喜欢的编程语言。请注意,600851475143太大,无法存储在32位整数中,这是问题的乐趣之一。

如果您有兴趣解决涉及素数的项目Euler问题,我谦虚地在我的博客上推荐文章Programming with Prime Numbers

相关问题