How can I test for primality?

前端 未结 16 2112
南方客
南方客 2020-12-05 08:29

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

相关标签:
16条回答
  • 2020-12-05 08:46

    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
    
    0 讨论(0)
  • 2020-12-05 08:47

    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)?

    0 讨论(0)
  • 2020-12-05 08:47

    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
    }
    
    0 讨论(0)
  • 2020-12-05 08:51

    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...).

    0 讨论(0)
  • 2020-12-05 08:51

    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...

    0 讨论(0)
  • 2020-12-05 08:53
    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...

    0 讨论(0)
提交回复
热议问题