Eratosthenes的筛子问题:处理真正的大数字

时间:2009-07-03 05:44:01

标签: java bignum sieve-of-eratosthenes

我正在使用Eratosthenes的Sieve解决Sphere的在线评判Prime Generator

我的代码适用于所提供的测试用例。但是......正如问题明确指出:

  

输入以数字t开头   测试用例在一行中(t <= 10)。   在接下来的每一行中都有   两个数m和n( 1 <= m <= n <=   分开的1000000000,n-m <= 100000)   一个空间。

我知道方法Integer.parseInt()在处理非常大的数字时抛出异常,并且在线判断表明正在抛出异常,所以我将parseInt的每个案例都更改为{{1}在我的代码中。

嗯,在Netbeans 6.5上运行正常,m和n的值很小。

parseLong

输入+输出:

package sphere;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main{

public static void runEratosthenesSieve(long lowerBound, long upperBound) {

      long upperBoundSquareRoot = (long) Math.sqrt(upperBound);

      boolean[] isComposite = new boolean[(int)upperBound + 1];

      for (int m = 2 /*int m = lowerBound*/; m <= upperBoundSquareRoot; m++) {

            if (!isComposite[m]) {

                if (m>=lowerBound) {System.out.println(m);}

                  for (int k = m * m; k <= upperBound; k += m)

                        isComposite[k] = true;

            }

      }

      for (int m = (int)upperBoundSquareRoot; m <= upperBound; m++)

            if (!isComposite[m])

                 if (m>=lowerBound){ System.out.println(m);}

}

public static void main(String args[]) throws java.lang.Exception{

       BufferedReader r = new BufferedReader(new InputStreamReader(System.in));


       String l = r.readLine();

       int testCases = Integer.parseInt(l); 

       for (int i =0; i<testCases; i++){
       String s =r.readLine();

       String []splitted=s.split(" ");


       long lowerBound = Long.parseLong (splitted[0]);
       long upperBound = Long.parseLong(splitted[1]);

       runEratosthenesSieve (lowerBound,upperBound);

       System.out.println("");
       }
}

}

但JCreator LE正在这样说:

run:
2
1 10
2
3
3
5
7

3 5
3
5

BUILD SUCCESSFUL (total time: 11 seconds)

这里我没有整数溢出,但为什么jcreator会抱怨?

考虑到临界测试用例,该程序也会破坏Netbeans:

2
1 10
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Long.parseLong(Long.java:424)
    at java.lang.Long.parseLong(Long.java:461)
    at sphere.Main.main(Main.java:51)

Process completed.

如何处理问题陈述中那些巨大的整数?

编辑:根据建议我更改了BitSet的布尔数组,但我仍然得到run: 2 999900000 1000000000 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at sphere.Main.runEratosthenesSieve(Main.java:13) at sphere.Main.main(Main.java:55) Java Result: 1

OutOFMemoryError

输入 - 输出:

package sphere;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.BitSet;

public class Main{

public static void runEratosthenesSieve(long lowerBound, long upperBound) {

      long upperBoundSquareRoot = (long) Math.sqrt(upperBound);

      //boolean[] isComposite = new boolean[(int)upperBound + 1];

      BitSet isComposite = new BitSet((int)upperBound+1);

      for (int m = 2 /*int m = lowerBound*/; m <= upperBoundSquareRoot; m++) {

            if (!isComposite.get(m)) {

                if (m>=lowerBound) {System.out.println(m);}

                  for (int k = m * m; k <= upperBound; k += m)

                        isComposite.set(m);

            }

      }

      for (int m = (int)upperBoundSquareRoot; m <= upperBound; m++)

            if (!isComposite.get(m))

                 if (m>=lowerBound){ System.out.println(m);}

}

public static void main(String args[]) throws java.lang.Exception{

       BufferedReader r = new BufferedReader(new InputStreamReader(System.in));


       String l = r.readLine();

       int testCases = Integer.parseInt(l); 

       for (int i =0; i<testCases; i++){
       String s =r.readLine();

       String []splitted=s.split(" ");


       long lowerBound = Long.parseLong (splitted[0]);
       long upperBound = Long.parseLong(splitted[1]);

       runEratosthenesSieve (lowerBound,upperBound);

       System.out.println("");
       }
}

}

5 个答案:

答案 0 :(得分:6)

这是你的问题:

boolean[] isComposite = new boolean[(int)upperBound + 1];

这将使用大量空间,因为它为每个布尔值分配4个字节,以便更快地访问。使用java.lang.BitSet来避免这种情况。

最终,您的数字可能会长得太长,您将不得不使用BigInteger。但在那时,Eratosthenes的筛子可能不会再削减它了。

答案 1 :(得分:1)

你正在用很多空间存放你的布尔值。您可能会尝试将每个布尔值压缩为一位。考虑一下,你是否真的需要为下限和上限之间的每个数字设置一个布尔值?例如,偶数从不是素数(2除外),也不是3的倍数(除了3)等等。This page可能会给你一些好的想法。

答案 2 :(得分:1)

您的BitSet实施中存在一个小错误。这一行:

                    isComposite.set(m);

实际应该是:

                    isComposite.set(k);

修复该行后,代码在测试用例999900000到1000000000上运行无错误,从999900017开始吐出4,832个素数,以999999937结束.BitSet使用125 MB内存,该方法需要17秒才能运行我的2.2 GHz笔记本电脑。

答案 3 :(得分:0)

你是否使用BigInteger类?因为如果没有,我强烈推荐这里。它将处理您描述的大数字。如果这还不够好,那么您需要通过将-Xmx作为命令行参数来为JVM分配更多内存。这里有一个例子:

http://www.coderanch.com/t/384456/Java-General-intermediate/java/Increase-JVM-heap-size-eclipse

如果您还需要十进制数字,那么还有一个BigDecimal。

答案 4 :(得分:0)

由于Java堆大小的限制,我遇到了类似的问题。而不是使用高内存整数,转换为布尔值解决了问题。 找到附加的代码:

24 = 7 + 7 + 10