【问题标题】:Java data-type issueJava 数据类型问题
【发布时间】:2013-11-03 23:57:47
【问题描述】:

我编写了一个函数来使用 Eratosthenes 筛法处理素数。该函数使用整数可以正常工作,但我现在正在尝试实现对 long 的支持,以便可以处理大数。

我似乎无法让函数与 long 一起使用,也看不出明显的原因。

错误是指来自类型转换等的典型精度警告,但我无法弄清楚是什么原因造成的:

   ./com/wkilgour/lang/Maths.java:21: error: possible loss of precision
        boolean[] isPrime = new boolean[n + 1];
                                          ^
  required: int
  found:    long
./com/wkilgour/lang/Maths.java:24: error: possible loss of precision
            isPrime[i] = true;
                    ^
  required: int
  found:    long
./com/wkilgour/lang/Maths.java:27: error: possible loss of precision
            if (isPrime[i])
                        ^
  required: int
  found:    long
./com/wkilgour/lang/Maths.java:29: error: possible loss of precision
                    isPrime[i * j] = false;
                              ^
  required: int
  found:    long
4 errors

函数如下:

public static boolean[] primeSieve(long n)
{
    boolean[] isPrime = new boolean[n + 1];

    for (long i = 2L; i <= n; i++)
        isPrime[i] = true;

    for (long i = 2L; i*i <= n; i++)
        if (isPrime[i])
            for (long j = i; i*j <= n; j++)
                isPrime[i * j] = false;

    return isPrime;
}

任何帮助将不胜感激!

【问题讨论】:

  • 你的错误信息是不是有点长?
  • 是的,有一些与精度有关的错误。我现在添加了完整的错误
  • 您是否考虑过需要多少内存才能知道高达long 值的数字的素数?
  • 使用分段筛子,将筛子分成更小的部分。 stackoverflow.com/questions/10249378/…

标签: java types long-integer primes sieve


【解决方案1】:

数组大小理论上最大为2^31-1,是一个整数。您的n+1 很长。所以这不匹配。您需要将n+1 转换为整数:

boolean[] isPrime = new boolean[(int) (n + 1)];

现在,您知道了理论,您应该意识到像这样为longs 实现筛子是行不通的,因为您将没有足够的内存,而 Java 根本不允许您创建数组尺寸大于 2^31-1。因此,只需将方法中的所有内容更改为int。这看起来像这样:

public static boolean[] primeSieve(int n)
{
    boolean[] isPrime = new boolean[n + 1];

    for (int i = 2; i <= n; i++)
        isPrime[i] = true;

    for (int i = 2; i*i <= n; i++)
        if (isPrime[i])
            for (int j = i; i*j <= n; j++)
                isPrime[i * j] = false;

    return isPrime;
}

为了优化大筛子的内存使用,我建议使用java.util.BitSet

public static BitSet primeSieve(int n)
{
    BitSet isPrime = new BitSet(n+1);

    for (int i = 2; i <= n; i++)
        isPrime.set(i);

    for (int i = 2; i*i <= n; i++)
        if (isPrime.get(i))
            for (int j = i; i*j <= n; j++)
                isPrime.set(i * j, false);

    return isPrime;
}

【讨论】:

  • 这是我最初的代码,它运行良好。我正在尝试使用比整数大得多的数字,但这就是为什么我想添加长支持
  • 您最好的选择是使用 BitSet,但这仍然不允许您实现 longs 算法,因为即使 BitSet 也只接受 2^31-1 位。使用 2^31-1 位创建 BitSet 将使用 2 GiB 的 ram。对 boolean[] 数组执行相同操作时,需要 16 GiB 的内存。
【解决方案2】:

我认为问题很简单:您应该使用整数值作为数组索引(即方括号内的值)。

public static boolean[] primeSieve(long n)
{
    boolean[] isPrime = new boolean[(int) (n + 1)];

    for (long i = 2L; i <= n; i++)
        isPrime[(int) i] = true;

    for (long i = 2L; i*i <= n; i++)
        if (isPrime[(int) i])
            for (long j = i; i*j <= n; j++)
                isPrime[(int) (i * j)] = false;

    return isPrime;
}

【讨论】:

    猜你喜欢
    • 2021-04-24
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 2018-10-27
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多