埃拉托斯特尼筛问题:处理非常大的数字

发布于 2024-07-26 05:34:55 字数 4774 浏览 5 评论 0 原文

我正在使用埃拉托斯特尼筛法求解 Sphere 的在线法官 素数生成器

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

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

我知道方法 Integer.parseInt() 在处理非常大的数字时会抛出异常,并且在线判断表明正在抛出异常,因此我更改了 parseInt 的每个情况 code> 到我的代码中的 parseLong

嗯,事情在 Netbeans 6.5 上运行良好,m 和 n 的值很小。

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("");
       }
}

}

输入+输出:

run:
2
1 10
2
3
3
5
7

3 5
3
5

BUILD SUCCESSFUL (total time: 11 seconds)

但是 JCreator LE 是这样说的:

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.

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

考虑到边界测试用例,程序在 Netbeans 上也会崩溃:

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

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

编辑:根据建议,我更改了 BitSet 的布尔数组,但仍然收到 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("");
       }
}

}

输入输出:

run:
1
999900000 1000000000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.BitSet.initWords(BitSet.java:144)
        at java.util.BitSet.<init>(BitSet.java:139)
        at sphere.Main.runEratosthenesSieve(Main.java:16)
        at sphere.Main.main(Main.java:58)
Java Result: 1
BUILD SUCCESSFUL (total time: 14 seconds)

I'm solving Sphere's Online Judge Prime Generator using the Sieve of Eratosthenes.

My code works for the test case provided. But.. as the problem clearly states:

The input begins with the number t of
test cases in a single line (t<=10).
In each of the next t lines there are
two numbers m and n (1 <= m <= n <=
1000000000, n-m<=100000)
separated by
a space.

I know that the method Integer.parseInt() throws an Exception when handling really big numbers and the online judge was indicating that an Exception was being thrown, so I changed every case of parseInt to parseLong in my code.

Well, the thing is running fine on Netbeans 6.5 with small values for m and n.

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("");
       }
}

}

Input+Output:

run:
2
1 10
2
3
3
5
7

3 5
3
5

BUILD SUCCESSFUL (total time: 11 seconds)

But JCreator LE is saying this:

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.

Here I don't have an integer overflow, but why would jcreator complain?

Considering the borderline testcase, the program implodes on Netbeans too:

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

How can I deal with those huge-ish integers of the problem statement?

Edit: By suggestion I have changed the boolean array for a BitSet, but I'm still getting an 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("");
       }
}

}

Input-Output:

run:
1
999900000 1000000000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.BitSet.initWords(BitSet.java:144)
        at java.util.BitSet.<init>(BitSet.java:139)
        at sphere.Main.runEratosthenesSieve(Main.java:16)
        at sphere.Main.main(Main.java:58)
Java Result: 1
BUILD SUCCESSFUL (total time: 14 seconds)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北渚 2024-08-02 05:34:55

这是你的问题:

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

这将使用大量的空间,因为它为每个布尔值分配 4 个字节以允许更快的访问。 使用 java.lang.BitSet 来避免那。

最终,您的数字也可能会变得太大,并且您将不得不使用 BigInteger。 但到那时,埃拉托斯特尼的筛子可能也不再适用了。

Here's your problem:

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

This will use a HUGE amount of space since it allocates 4 bytes per boolean in order to allow faster access. Use a java.lang.BitSet to avoid that.

Eventually, your numbers might get too big for long as well and you'll have to use BigInteger. But at that point, the sieve of Eratosthenes will probably not cut it anymore as well.

待"谢繁草 2024-08-02 05:34:55

您使用了大量空间来存储布尔值。 您可能会尝试将每个布尔值压缩为一位。 想想看,您真的需要为下限和上限之间的每个数字提供一个布尔值吗? 例如,偶数永远不是质数(2 除外),也不是 3 的倍数(3 除外)等。 此页面可能会给您一些好主意。

You're using a lot of space to store your booleans. You might try to squeeze every boolean into one bit. And think about it, do you realy need a boolean for every number between lowerbound and upperbound? The even numbers for instance are never prime (except for 2), nor are all multiples of 3 (except for 3) etc. This page might give you some good ideas.

宣告ˉ结束 2024-08-02 05:34:55

您的 BitSet 实现中有一个小错误。 该行:

                    isComposite.set(m);

实际上应该是:

                    isComposite.set(k);

修复该行后,代码在测试用例 999900000 到 1000000000 上运行没有错误,吐出以 999900017 开头并以 999999937 结尾的 4,832 个素数。 BitSet 使用了 125 MB 内存,该方法占用了 17在我的 2.2 GHz 笔记本电脑上运行几秒钟。

There was a small bug in your BitSet implementation. The line:

                    isComposite.set(m);

should actually be:

                    isComposite.set(k);

With that line fixed, the code ran without errors on the test case 999900000 to 1000000000, spitting out 4,832 primes beginning with 999900017 and ending with 999999937. The BitSet used 125 Mbytes of memory, and the method took 17 seconds to run on my 2.2 GHz laptop.

潇烟暮雨 2024-08-02 05:34:55

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

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

如果您需要十进制数大,还有一个 BigDecimal出色地。

Ae you using the BigInteger class? Because if no, I highly recommend it here. It will deal with the big numbers you are describing. If that is not good enough, then you need to allocate more memory for the JVM to use by doing -Xmx as a command line parameter. There's an example here:

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

There is a BigDecimal as well, if you need decimal numbers to be large as well.

世界如花海般美丽 2024-08-02 05:34:55

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

public ArrayList<Integer> sieve(int A) {
    boolean prime [] = new boolean[A + 1];
    Arrays.fill(prime, true);
    prime[0] = prime[1] = false;

    for (int i = 2; i <= A; i++) {
        if (!prime[i])
            continue;

        for (long j = 1L * i * i; j <= (long) A; j += i)
            prime[(int) j] = false;
    }

    ArrayList<Integer> res = new ArrayList<>();

    for (int i = 0; i <= A; i++) {
        if (prime[i])
            res.add(i);
    }

    return res;
}

I had faced similar issues due the limitations on Java Heap Size. Instead of using high memory Integer, shifting to boolean solved the problem.
Find the attached code:

public ArrayList<Integer> sieve(int A) {
    boolean prime [] = new boolean[A + 1];
    Arrays.fill(prime, true);
    prime[0] = prime[1] = false;

    for (int i = 2; i <= A; i++) {
        if (!prime[i])
            continue;

        for (long j = 1L * i * i; j <= (long) A; j += i)
            prime[(int) j] = false;
    }

    ArrayList<Integer> res = new ArrayList<>();

    for (int i = 0; i <= A; i++) {
        if (prime[i])
            res.add(i);
    }

    return res;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文