C#找梅森素數

C#找梅森素數

梅森素數是由梅森數而來。

所謂梅森數,是指形如2p-1的一類數,其中指數p是素數,常記爲Mp 。如果梅森數是素數,就稱爲梅森素數。比如2^2-1=3,2^3-1=7,2^5-1=31,2^7-1=127,指數P也是素數,同時也用M2,M3,M5,M7表示。

用因式分解法可以證明,若2n-1是素數,則指數n也是素數;反之,當n是素數時,2n-1(即Mp)卻未必是素數。前幾個較小的梅森數大都是素數,然而梅森數越大,梅森素數也就越難出現。

2008年8月23日,美國加州大學洛杉磯分校的計算機專家史密斯終於發現超過1000萬位的梅森素數 。 它有12978189位數,如果用普通字號將這個巨數連續打印下來,它的長度可超過50公里!這一成就被美國的《時代》雜誌評爲 “2008年度50項最佳發明” 之一,排名在第29位。

2013年1月,美國中央密蘇里大學數學教授柯蒂斯·庫珀領導的研究小組發現了第48個梅森素數 。[12] 這一發現被英國《新科學家》週刊評爲當年自然科學十大突破之一。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ConAppPrimeNumber2
{
    //Mersenne prime number 
    //梅森素數的公式2^P-1(用2的冪次方減1表示,其中P也是一個素數)
    //比如2^2-1=3,2^3-1=7,2^5-1=31,2^7-1=127,指數P也是素數
    //同時也用M2,M3,M5,M7表示

    class Program
    {
        static void Main(string[] args)
        {

            System.Diagnostics.Stopwatch s = new Stopwatch();


            PrimeNumber.testPower();
            System.Console.WriteLine();

            s.Reset();
            s.Start();
            PrimeNumber.Find5();
            s.Stop();
            System.Console.WriteLine("Watch Time:{0}m, {1}s, {2}ms", s.Elapsed.Minutes, s.Elapsed.Seconds, s.ElapsedMilliseconds);

            System.Console.WriteLine();

            s.Reset();
            s.Start();
            PrimeNumber.Find6();
            s.Stop();
            System.Console.WriteLine("Watch Time:{0}m, {1}s, {2}ms", s.Elapsed.Minutes, s.Elapsed.Seconds, s.ElapsedMilliseconds);
        }
    }


    public class PrimeNumber
    {
        static int n = 100000;   //查找100(n=100)以內的素數    
        //static int n = 1000000;
        static bool IsPN = false;  //找到素數就設置爲true
        static int count = 0;   //計數器

        //找梅森素數,方式一(從質數中去找)//性能低,找到第五位M17(耗時10分鐘)
        //經過優化代碼後,找到第六位M19(耗時30秒)//M31 -> 2ms //終於找天第九位M61(耗時2分10秒)
        public static void Find5()
        {
            IsPN = false;
            //System.Console.Write(2 + "\t"); //素數2還是在這裏輸出
            //count = 1;

            count = 0;

            int MaxMP = 63; //不能設置成64,因爲0~63其實就已經是64位了,long最大就是64位,2^64已經歸零了,就好比bit=0~255,2^8-1        
            long MaxMPN = PowerOfTwo(MaxMP) - 1;

            //int temp = 2;//從指數2開始,p=2              

            for (long i = 1; i < long.MaxValue; i += 2)
            {

                for (long j = 3; j < i; j += 2)     //此處的i=3也不會被執行,因爲j<i,不滿足條件,就算j<=i,那麼i%j也會把3=i認爲是合數
                {
                    if (i % j == 0)
                    {
                        IsPN = false;
                        break;
                    }

                    if (j * j > i)
                    //if(j> Math.Sqrt(i))     
                    {
                        IsPN = true;
                        break;
                    }
                }

                if (i == 2 || i == 3) IsPN = true;     //2不會被執行,因爲前面的循環是(i=1;i+=2)
                //if (i == 3) IsPN = true;             //素數3因爲要參與是否是梅森素數的計算,所以放在這裏

                if (IsPN)
                {
                    //System.Console.Write(i + "\t");
                    //count++;

                    for (int p = 2; p <= MaxMP; p++)
                    //for (int p = temp; p <= MaxMP; p++)
                    {
                        //if (p != 2 && p % 2 == 0) continue;   //M62執行不了,死循環,設置成61時看不出問題來
                        //if (p != 3 && p % 3 == 0) continue;   //M63同樣

                        long MP = PowerOfTwo(p) - 1;

                        if (i < MP)
                        {
                            i = MP - 2;
                            break;
                        }

                        if (i == MP)
                        {
                            count++;
                            System.Console.Write("[No.{0} M{1}] ", count, p);
                            System.Console.Write("Mersenne prime number: 2^{0}-1={1}" + "\n", p, i);
                            if (p == MaxMP) return;             //如果已經找到就退出,後面的i循環就不需要再執行(比如設置MaxMP爲32,比較完M32,則i=M32~long.MaxValue就不執行)
                            //temp = p + 1;                     //前面的就不比較,已經測試,性能並無提升       
                            //i = PowerOfTwo(p + 1) - 1 - 2;      //不減2會漏掉 M3 => 2^3-1=7      //M61 -> 2.23m  
                            i = MP;                           //前面的就不比較                  //M61 -> 3.10m                                             
                            break;
                        }

                    }

                }
                else
                {
                    if (i > MaxMPN) return;//如果已經把最大的2^MaxMP-1比較完,就退出程序。
                }
            }
            System.Console.WriteLine("Count: {0}", count);
        }

        //找梅森素數,方式二(從梅森數中去找梅森素數)//性能高,能夠找到第八位M31(耗時15秒)//第九位找到了,M61 -> 23s
        //梅森數:滿足條件2^P-1,但這個數不一定是素數,比如2^4-1=15
        //梅森素數:比如2^3-1=7
        public static void Find6()
        {
            IsPN = false;
            count = 0;

            //已知梅森指數MP:P=2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, ...目前發現最大的P=57,885,161,是第48位,其長度有17,425,170位
            //已知梅森素數:3, 7, 31, 127, 8191, 131071, 524287, 2147483647, ...

            //因爲long最大就是64位,所以只能計算到64位
            for (int p = 2; p <= 64; p++)
            {
                long MP = (PowerOfTwo(p) - 1);
                long MPSqrt = p % 2 == 0 ? PowerOfTwo(p / 2) : PowerOfTwo((p + 1) / 2);
                //long MPSqrt =(long)Math.Sqrt(MP);//使用.NET內置對象數學函數求值(開平方根)


                for (long j = 3; j < (MP); j += 2)
                {
                    //System.Console.Title = j.ToString();//注意指數P小於20可以使用,否則容易死機
                    if (MP % j == 0)
                    {
                        IsPN = false;
                        System.Console.Write("Is not Mersenne prime number:2^{0}-1={1}" + "\n", p, MP);//滿足條件2^P-1,但不是梅森素數
                        break;
                    }
                    //if (j * j > (MP))       
                    if (j > MPSqrt)
                    {
                        IsPN = true;
                        break;
                    }
                }

                if (p == 2) IsPN = true;//當指數p爲2時,將得到素數3,因爲要參與是否是梅森素數的計算,所以在這裏加上這個條件

                if (IsPN)
                {
                    count++;
                    System.Console.Write("[No.{2} M{3}] Mersenne prime number: 2^{0}-1={1}" + "\n", p, MP, count, p);//梅森素數
                }

            }
            System.Console.WriteLine("Count: {0}", count);
        }


        //鎖定梅森素數的範圍
        public static long PowerOfTwo(int p)
        {
            long num = 2;

            //if (p == 0) return 1;
            //if (p == 1) return 2;

            switch (p)
            {
                case 0:
                    num = 1;
                    break;
                case 1:
                    num = 2;
                    break;
                default:
                    num = 2;
                    break;
            }

            for (int i = 1; i < p; i++)
            {
                num *= 2;
            }
            return num;
        }

        public static void testPower()
        {
            for (int i = 0; i <= 64; i++)
            {
                System.Console.Write("2^{0}={1}" + "\t", i, PowerOfTwo(i));
            }
        }
    }
}

寫這篇文章時梅森素數還只發現48個,今天整理了下代碼,才知道現在已經發現第49個了。

2016年1月7日,庫珀又發現第49個梅森素數 274207281-1。這個超大素數有22338618位,是目前已知的最大素數。

版權所有,轉載請註明文章出處 http://blog/csdn.net/cadenzasolo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章