Euler discovered the remarkable quadratic formula:
\$n^2 + n + 41\$
It turns out that the formula will produce \40ドル\$ primes for the consecutive values \$n = 0\$ to \39ドル\$. However, when \$n = 40, 40^2 + 40 + 41 = > 40(40 + 1) + 41\$ is divisible by \41ドル\,ドル and certainly when \$n = 41, 41^2 + 41 + 41\$ is clearly divisible by \41ドル\$.
The incredible formula \$n^2 − 79n + 1601\$ was discovered, which produces \80ドル\$ primes for the consecutive values \$n = 0\$ to \79ドル\$. The product of the coefficients, \$−79\$ and \1601ドル\,ドル is \$−126479\$.
Considering quadratics of the form:
\$n^2 + an + b\,ドル where \$|a| < 1000\$ and \$|b| < 1000\$
where \$|n|\$ is the modulus/absolute value of \$n\$ e.g. \$|11| = 11\$ and \$|−4| = 4\$ Find the product of the coefficients, \$a\$ and \$b\,ドル for the quadratic expression that produces the maximum number of primes for consecutive values of \$n\,ドル starting with \$n = 0\$.
My Implementation:
I used Sieve of Eratosthenes for finding primes. I also used a HashSet for fast searching.
static void Main()
{
HashSet<int> primes = Primes(10000000);
Func<int,int,int,int> f = (a,b,n) => n * n + a * n + b;
int maxCount = int.MinValue;
int x = 0;
int y = 0;
for(int a = -999;a < 1000;a++)
{
for(int b = -999;b < 1000;b++)
{
int count = 0;
int n = 0;
while(primes.Contains(f(a,b,n++))) count++;
if(count > maxCount)
{
maxCount = count;
x = a;
y = b;
}
}
}
Console.WriteLine("x * y = {0}",x * y);
}
static HashSet<int> Primes(int n)
{
HashSet<int> primes = new HashSet<int>();
BitArray a = new BitArray(n+1,true);
for(int i = 2;i <= Math.Sqrt(n);i++)
{
if(a[i])
{
for(int j = i * i;j <= n;j += i)
{
a[j] = false;
}
}
}
for(int i = 2;i < a.Length;i++)
{
if(a[i]) primes.Add(i);
}
return primes;
}
How can I improve this? Can you offer a more efficient implementation?
2 Answers 2
There is one relatively simple optimization you can do, for a start, and it will likely make a big difference...
If you analyze the equation:
n2 + an + b, where |a| < 1000 and |b| < 1000
you need to solve it for where n2 + an + b
is prime.
The first n
value to use is 0. 02 +a0 +b
is b
, thus, in order to process any values, it is clear that b
needs to be a prime number (and not negative either...).
Thus, you should rearrange your loops, and your outer loop should be on the first k
prime numbers in your set, where the k'th prime is < 1000.
There are 168 primes less than 1000, so that will reduce your loops from 2000 'b' loops to just 168.
Similarly, when you loop on only those 168 primes, you are guaranteed that the n == 0
result is prime, and you only need to test on the n > 0
condition.
Further, when n
is 1, the equation becomes:
1 + a + b = prime
or, since you have primes already from your sieve, you can significantly restrict the data-set by doing:
a = prime - b - 1
for primes in the range of b - 998
through to b + 1000
(which will keep a
within the limits of -999 to +999). Note that there are no primes less than 2, and only a few hundred primes less than the 'worst case' (b ==999) + 1000
Only if you satisfy those two conditions would I consider even calling the prime function f(a,b,n++)
Another fairly major optimization in your Sieve algorithm, is do away with the hashset. If the index of the bitarray is true that number is prime. Also on a more minor vein, since 2 is the most unique prime, being even, if you loop through all the even numbers first, this greatly reduces the inner loop for the odd numbers since you only need to step the odd multiples:
static BitArray Primes(int n)
{
BitArray a = new BitArray(n + 1, true);
int limit = (int)Math.Sqrt(n);
a[0] = false;
a[1] = false;
for (int i = 4; i <= limit; i += 2)
{
a[i] = false;
}
for (int i = 3; i <= limit; i += 2)
{
if (a[i])
{
int step = i * 2;
for (int j = i * i; j <= n; j += step)
{
a[j] = false;
}
}
}
return a;
}
-
\$\begingroup\$ Maybe my conversion to Swift wasn't complete, but it seems as though using a limit of sqrt(n) effectively cuts out a large number of confirmed prime number. \$\endgroup\$Greg Combs– Greg Combs2015年08月22日 19:25:09 +00:00Commented Aug 22, 2015 at 19:25
Explore related questions
See similar questions with these tags.
HashSet<int> primes = Primes(10000000);
\$\endgroup\$