我正在解决项目欧拉问题,我目前排在第10位。
首先:我知道还有其他解决方案,我目前正在使用Eratosthenes的筛子编写另一种方法。 我希望您的帮助是理解为什么此代码不起作用。
这是我的代码(问题涉及查找每个素数低于200万的总和)。素数检查方法似乎工作正常,但结果比应有的少。
class Euler10
{
public static void Main()
{
long sum = 0; // Was originally an int. Thanks Soner Gönül!
for(int i = 1; i < 2000000; i++)
{
if (CheckIfPrime(i) == true)
sum += i;
}
System.Console.WriteLine(sum);
System.Console.Read();
}
static bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
for (int i = 3; i*i < number; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
}
我得到的数字是1,308,111,344,比它应该低两个数量级。代码很简单,我对此错误感到困惑。
编辑:总结很长时间解决了数字问题,谢谢大家!现在,我得到了143042032112作为答案:CheckIfPrime()中的i * i并不总是正确的。 使用sqrt()函数并添加一个(以补偿int cast)会得到正确的结果。这是正确的CheckIfPrime()函数:
bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
int max = 1 + (int)System.Math.Sqrt(number);
for (int i = 3; i < max; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
编辑2: Ness会帮助我进一步优化代码(计算数字的平方根并将其与i进行比较比提升i ^ 2慢,然后将其与数字进行比较):问题与原始方法是它没有考虑到数字是i的确切平方的边缘情况,因此有时返回true而不是false。然后,CheckIfPrime()的正确代码是:
bool CheckIfPrime(int number)
{
if (number <= 1)
return false;
if (number == 2)
return true;
if (number % 2 == 0)
return false;
for (int i = 3; i*i <= number; i += 2)
{
if ((number % i) == 0)
return false;
}
return true;
}
再次感谢大家!
答案 0 :(得分:3)
您的代码无效,因为它尝试使用32位int
来保存超过32位变量中最高值的数字。问题的答案是142,913,828,922
,需要38位。
将sum
的数据类型更改为long
可以解决此问题。
答案 1 :(得分:2)
您正在使用sum
32-bit
变量2,147,483,647
,但您尝试将其分配给143,042,032,112
以上32
。
但是你的结果是64
,它需要比long sum = 0;
更多的位来存储它。
将其类型设置为int
,其中存储{{1}}位。
{{1}}
这是一个有效的Int32.Maximum
。
答案 2 :(得分:2)
使用long应该有所帮助。http://msdn.microsoft.com/en-us/library/ctetwysk.aspx 给你一个64位整数,其中int只有32位。
答案 3 :(得分:2)
for (... i=3 ; i*i < number; i+=2 )
错了。它应该是
for (... i=3 ; i*i <= number; i+=2 )
...
i
和number
必须属于同一类型的课程;这几乎永远不会给你一个溢出,因为你从3 开始(除非number
非常大,接近类型范围的上限)。
比较应具有包容性,以捕捉number
是素数平方的情况。
答案 4 :(得分:1)
你的算法不是 Eratosthenes的筛子;模运算符将它放弃。您的算法是由奇数进行的试验除法。这是一个使用Eratosthenes筛选的函数:
function sumPrimes(n)
sum := 0
sieve := makeArray(2..n, True)
for p from 2 to n step 1
if sieve[p]
sum := sum + p
for i from p * p to n step p
sieve[i] := False
return sum
致电sumPrimes(2000000)
给出了答案,我不会因为尊敬Project Euler而写下这些答案。该函数在时间O( n 日志日志 n )中运行,这比原始程序的O( n ^ 2)要好得多。有更好的筛选方法,但这很简单,容易正确,并且对于大多数目的而言都足够好,包括你的。你应该在不到一秒的时间内得到答案。
我会留给你用适当的数据类型翻译成C#。
如果您对此问题的某个较大版本感兴趣,我在我的博客上计算了the sum of the first billion primes: