I am writing a little library with some prime number related methods. As I\'ve done the groundwork (aka working methods) and now I\'m looking for some optimization. Ofcours
In case anyone else is interested, here's my conversion of Mohammad's procedure above to VBA. I added a check to exclude 1, 0, and negative numbers as they are all defined as not prime.
I have only tested this in Excel VBA:
Function IsPrime(input_num As Long) As Boolean
Dim i As Long
If input_num < 2 Then '1, 0, and negative numbers are all defined as not prime.
IsPrime = False: Exit Function
ElseIf input_num = 2 Then
IsPrime = True: Exit Function '2 is a prime
ElseIf input_num = 3 Then
IsPrime = True: Exit Function '3 is a prime.
ElseIf input_num Mod 2 = 0 Then
IsPrime = False: Exit Function 'divisible by 2, so not a prime.
ElseIf input_num Mod 3 = 0 Then
IsPrime = False: Exit Function 'divisible by 3, so not a prime.
Else
'from here on, we only need to check for factors where
'6k ± 1 = square root of input_num:
i = 5
Do While i * i <= input_num
If input_num Mod i = 0 Then
IsPrime = False: Exit Function
ElseIf input_num Mod (i + 2) = 0 Then
IsPrime = False: Exit Function
End If
i = i + 6
Loop
IsPrime = True
End If
End Function
I posted a class that uses the sieve or Eratosthenes to calculate prime numbers here:
Is the size of an array constrained by the upper limit of int (2147483647)?
Repeat mode operations will run very slowly. Use the eratosthenes grid to get the prime list in order.
/*
The Sieve Algorithm
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
*/
numbers = new MyBitArray(limit, true);
for (long i = 2; i < limit; i++)
if (numbers[i])
for (long j = i * 2; j < limit; j += i)
numbers[j] = false;
}
public class MyBitArray: IDisposable
{
byte[] bytes;
public MyBitArray(long limit, bool defaultValue = false)
{
long byteCount = (limit & 7) == 0 ? limit >> 3 : (limit >> 3) + 1;
this.bytes = new byte[byteCount];
for(long i = 0; i < byteCount; i++)
{
bytes[i] = (defaultValue == true ? (byte)0xFF : (byte)0x00);
}
this.limit = limit;
}
public MyBitArray(long limit, byte[] bytes)
{
this.limit = limit;
this.bytes = bytes;
}
public bool this[long index]
{
get
{
return getValue(index);
}
set
{
setValue(index, value);
}
}
bool getValue(long index)
{
if (index < 8)
{
return getBit(bytes[0], (byte)index);
}
long byteIndex = (index & 7) == 0 ? ((index >> 3) - 1) : index >> 3;
byte bitIndex = (byte)(index & 7);
return getBit(bytes[byteIndex], bitIndex);
}
void setValue(long index, bool value)
{
if (index < 8)
{
bytes[0] = setBit(bytes[0], (byte)index, value);
return;
}
long byteIndex = (index & 7) == 0 ? (index >> 3) - 1 : index >> 3;
byte bitIndex = (byte)(index & 7);
bytes[byteIndex] = setBit(bytes[byteIndex], bitIndex, value);
}
bool getBit(byte byt, byte index)
{
return ((byt & (1 << index)) >> index) == 1;
}
byte setBit(byte byt, byte index, bool value)
{
return (byte)((byt & ~(1 << index)) + (value ? 1 << index : 0));
}
public void Dispose()
{
GC.Collect(2, GCCollectionMode.Optimized);
}
private long limit;
public long Limit { get { return limit; } }
public byte[] Bytes { get { return this.bytes; } }
}
However, I would suggest you a much better method for prime number testing. For 64 bit numbers, no matter how large the number is, it gives the exact result in milliseconds.
public static bool IsPrime(ulong number)
{
return number == 2
? true
: (BigInterger.ModPow(2, number, number) == 2
? (number & 1 != 0 && BinarySearchInA001567(number) == false)
: false)
}
public static bool BinarySearchInA001567(ulong number)
{
// Is number in list?
// todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
// Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}
I guess this is your problem:
for (int idx = 3; idx < flooredAndSquared; idx++)
This should be
for (int idx = 3; idx <= flooredAndSquared; idx++)
so you don't get square numbers as primes. Also, you can use "idx += 2" instead of "idx++" because you only have to test odd numbers (as you wrote in the comment directly above...).
As Mark said, the Miller-Rabin test is actually a very good way to go. An additional reference (with pseudo-code) is the Wikipedia article about it.
It should be noted that while it is probabilistic, by testing just a very small number of cases, you can determine whether a number is prime for numbers in the int (and nearly long) range. See this part of that Wikipedia article, or the Primality Proving reference for more details.
I would also recommend reading this article on modular exponentiation, as otherwise you're going to be dealing with very very large numbers when trying to do the Miller-Rabin test...
private static bool IsPrime(int number) {
if (number <= 3)
return true;
if ((number & 1) == 0)
return false;
int x = (int)Math.Sqrt(number) + 1;
for (int i = 3; i < x; i += 2) {
if ((number % i) == 0)
return false;
}
return true;
}
I can't get it any faster...