【问题标题】:project euler #10, java, correct for small numbers项目 euler #10,java,适用于小数字
【发布时间】:2017-07-20 02:06:07
【问题描述】:

*免责声明,当我说“我已经验证这是正确的结果”时,请解释这一点,因为我已经根据 WolframAlpha 的答案检查了我的解决方案,我认为这非常准确。

*目标,求所有小于或等于2,000,000(两百万)的素数之和

*问题,只要我的测试值范围大约小于或等于,我的代码就会输出正确的结果

一旦测试输入大于大约 1,300,000,我就不会输出正确的结果;我的输出将关闭...

测试输入:----199,999 测试输出:---1,709,600,813 正确结果:1,709,600,813

测试输入:----799,999 测试输出:---24,465,663,438 正确结果:24,465,663,438

测试输入:----1,249,999 测试输出:---57,759,511,224 正确结果:57,759,511,224

测试输入:----1,499,999 测试输出:--- 82,075,943,263 正确结果:82,074,443,256

测试输入:----1,999,999 测试输出:--- 142,915,828,925 正确结果:142,913,828,925

测试输入:----49,999,999 测试输出:--- 72,619,598,630,294 正确结果:72,619,548,630,277

*我的代码,发生了什么,为什么它适用于较小的输入?我什至用了 long,而不是 int...

long n = 3;
long i = 2;
long prime = 0;
long sum = 0;
while (n <= 1999999) {
  while (i <= Math.sqrt(n)) {    // since a number can only be divisible by all
                            // numbers
                            // less than or equal to its square roots, we only
                            // check from i up through n's square root!
    if (n % i != 0) {       // saves computation time
      i += 2;               // if there's a remainder, increment i and check again
    } else {
      i = 3;                // i doesn't need to go back to 2, because n+=2 means we'll
                            // only ever be checking odd numbers
      n += 2;               // makes it so we only check odd numbers
    }
  }                         // if there's not a remainder before i = n (meaning all numbers from 0
                            // to n were relatively prime) then move on
  prime = n;                // set the current prime to what that number n was
  sum = sum + prime;
  i = 3;                    // re-initialize i to 3
  n += 2;                   // increment n by 2 so that we can check the next odd number

}
System.out.println(sum+2); // adding 2 because we skip it at beginning

请帮忙:)

【问题讨论】:

  • 作为一个实验,您是否尝试过使用 java 的 BigInteger 类?
  • @mba12 我还没有……我正在上大学的编程入门课,我试图仅将我在课堂上学到的知识结合起来,回答欧拉项目的问题...
  • 另一个想法...您正在接近并超过 int max_value。通常,当您将 int 和 long 混合在一起时,int 会被转换为 long。但是在某些情况下,long 可以向下转换为 int。所以为了安全起见,你可能想在你的整数常量后面加上一个字母“L”。看看是否有帮助。见:stackoverflow.com/questions/3073862/java-arithmetic-int-vs-long
  • 问题不在于溢出。如果你得到的最高值是 142,913,828,925 这样的数字,那正好在 longs 的范围内,其中最高的是 9,223,372,036,854,775,807。
  • 提示:打印小限制的素数,例如小于 10 的所有素数之和...

标签: java primes


【解决方案1】:

问题是您没有正确检查要添加到总和中的最新素数是否小于限制。你有两个嵌套循环,但你只检查外循环的限制:

while (n <= 1999999) {

但是你不检查内部循环:

 while (i <= Math.sqrt(n)) {

但是,您在该循环中反复前进到下一个候选素数 (n += 2;)。这允许候选素数超过限制,因为限制只检查外循环每次迭代中的第一个候选素数,而不检查内循环访问的任何后续候选素数。

举个例子,在限制值为 1,999,999 的情况下,这让the next prime after 1,999,999, which is 2,000,003 进入。您会注意到,the correct value, 142,913,828,922, 比您的结果 142,915,828,925 少 2,000,003。

更简单的结构

这是代码结构的一种方式,使用标签和带有该标签的continue 来简化结构:

public static final long primeSum(final long maximum) {
    if (maximum < 2L) return 0L;
    long sum = 2L;

    // Put a label here so that we can skip to the next outer loop iteration.
    outerloop:
    for (long possPrime = 3L; possPrime <= maximum; possPrime += 2L) {
        for (long possDivisor = 3L; possDivisor*possDivisor <= possPrime; possDivisor += 2L) {
            // If we find a divisor, continue with the next outer loop iteration.
            if (possPrime % possDivisor == 0L) continue outerloop;
        }
        // This possible prime passed all tests, so it's an actual prime.
        sum += possPrime;
    }

    return sum;
}

【讨论】:

  • +1 但我们不能只比较除数的平方而不是使用平方根吗? possDivisor * possDivisor &lt;= possPrime
  • 我对此进行了测试,令我惊讶的是,它看起来速度差不多,所以我将对其进行更改以简化答案。我认为另一种方法也更快,我会考虑添加它。
  • 平方根在外循环中只计算一次,但它是递归的;乘法被多次调用,每次内部循环的交互一次,但这大部分很快就会终止。更好的方法是存储找到的素数并仅除以这些素数 - 只需要大约 1/10 的时间
  • @ChaiT.Rex 谢谢,这绝对有帮助。我唯一不明白的是为什么代码适用于所有小于约 130 万的输入值....
  • @BlueDevilSteve CarlosHeuberger 在您的问题下的评论显示了一个反例。当限制低至 10 时,您的原始代码会失败。而不是 2 + 3 + 5 + 7 = 17,它会添加另一个 11 来得到 28。
猜你喜欢
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
  • 1970-01-01
相关资源
最近更新 更多