วิธีที่สวยงามที่สุดในการสร้างจำนวนเฉพาะ [ปิด]


84

วิธีใดที่สวยงามที่สุดในการใช้ฟังก์ชันนี้:

ArrayList generatePrimes(int n)

ฟังก์ชันนี้จะสร้างช่วงแรกn(แก้ไข: ที่n>1) ดังนั้นgeneratePrimes(5)จะส่งกลับไฟล์ArrayList{2, 3, 5, 7, 11}ด้วย (ฉันกำลังทำสิ่งนี้ใน C # แต่ฉันพอใจกับการใช้งาน Java - หรือภาษาอื่น ๆ ที่คล้ายกันสำหรับเรื่องนั้น (ไม่ใช่ Haskell))

ฉันรู้วิธีเขียนฟังก์ชันนี้ แต่เมื่อคืนที่ผ่านมามันไม่ได้ออกมาดีอย่างที่หวัง นี่คือสิ่งที่ฉันคิดขึ้น:

ArrayList generatePrimes(int toGenerate)
{
    ArrayList primes = new ArrayList();
    primes.Add(2);
    primes.Add(3);
    while (primes.Count < toGenerate)
    {
        int nextPrime = (int)(primes[primes.Count - 1]) + 2;
        while (true)
        {
            bool isPrime = true;
            foreach (int n in primes)
            {
                if (nextPrime % n == 0)
                {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime)
            {
                break;
            }
            else
            {
                nextPrime += 2;
            }
        }
        primes.Add(nextPrime);
    }
    return primes;
}

ฉันไม่กังวลเกี่ยวกับความเร็วมากเกินไปแม้ว่าฉันไม่ต้องการให้มันไร้ประสิทธิภาพอย่างเห็นได้ชัด ฉันไม่สนใจว่าจะใช้วิธีไหน (ไร้เดียงสาหรือตะแกรงหรืออย่างอื่น) แต่ฉันต้องการให้มันค่อนข้างสั้นและชัดเจนว่ามันทำงานอย่างไร

แก้ไข : ขอบคุณทุกคนที่ตอบกลับแม้ว่าหลายคนจะไม่ตอบคำถามที่แท้จริงของฉัน เพื่อย้ำอีกครั้งว่าฉันต้องการโค้ดที่สะอาดและสร้างรายการจำนวนเฉพาะ ฉันรู้วิธีทำหลายวิธีแล้ว แต่ฉันมักจะเขียนโค้ดไม่ชัดเจนเท่าที่ควร ในหัวข้อนี้มีการเสนอตัวเลือกที่ดีบางประการ:

  • รุ่นที่ดีกว่าเดิมของสิ่งที่ฉันมี (Peter Smit, jmservera และ Rekreativc)
  • การใช้ตะแกรง Eratosthenes ที่สะอาดมาก (starblue)
  • ใช้ Java ของBigIntegers และnextProbablePrimeสำหรับโค้ดที่ง่ายมากแม้ว่าฉันจะนึกไม่ออกว่ามันจะมีประสิทธิภาพเป็นพิเศษ (dfa)
  • ใช้ LINQ เพื่อสร้างรายการราคา (Maghis) อย่างเกียจคร้าน
  • ใส่ข้อความจำนวนมากในไฟล์ข้อความและอ่านเมื่อจำเป็น (ดาริน)

แก้ไข 2 : ฉันได้ใช้ C #สองวิธีที่ระบุไว้ที่นี่และอีกวิธีหนึ่งที่ไม่ได้กล่าวถึงที่นี่ พวกเขาทั้งหมดค้นหาn primes แรกได้อย่างมีประสิทธิภาพ (และฉันมีวิธีการที่ดีในการหาขีด จำกัด ที่จะให้กับ sieves)


12
ไม่และไม่ใช่สำหรับ Project Euler เช่นกัน :-)
David Johnstone

1
มันจะดีกว่าสำหรับฉันที่จะทำซ้ำ <int> และยอม
แพ้

4
สิ่งที่ฉันอยากรู้คือวิธีใดเป็นวิธีที่หรูหราน้อยที่สุดในการสร้างจำนวนเฉพาะ ฉันกำลังคิดอะไรบางอย่างที่เกี่ยวข้องกับฐานข้อมูล Access?
j_random_hacker

1
สำหรับการเปรียบเทียบรหัส Haskell 2008 โดย BMephnubBy (((>1).).gcd) [2..] : มันจะทิ้งเฉพาะจำนวนที่ไม่ซ้ำกันระหว่างจำนวนธรรมชาติโดยเริ่มจาก 2 ในขณะที่พิจารณาว่าซ้ำกันจำนวนใด ๆ ที่มีจำนวนที่gcdพบก่อนหน้านี้มากกว่า 1 มันไม่มีประสิทธิภาพมากกำลังสองในจำนวนไพรม์ที่เกิดขึ้น แต่ก็สง่างาม .
Will Ness

ส่วนใหญ่สง่างาม , IMO เป็นของ Haskell import Data.List.Ordered ; let { _Y g = g (_Y g) ; primes = 2 : _Y( (3:) . minus [5,7..] . unionAll . map (\p-> [p*p, p*p+p*2..]) ) }แต่ที่เป็นของหลักสูตรทั้งหมดความคิดเห็นตาม
Will Ness

คำตอบ:


48

ใช้ค่าประมาณ

pi(n) = n / log(n)

สำหรับจำนวนไพรม์สูงสุด n เพื่อหาขีด จำกัด จากนั้นใช้ตะแกรง ค่าประมาณจะประเมินจำนวน primes ต่ำไปเล็กน้อยดังนั้นตะแกรงจะใหญ่กว่าที่จำเป็นเล็กน้อยซึ่งก็โอเค

นี่คือตะแกรง Java มาตรฐานของฉันคำนวณล้านครั้งแรกในเวลาประมาณหนึ่งวินาทีบนแล็ปท็อปปกติ:

public static BitSet computePrimes(int limit)
{
    final BitSet primes = new BitSet();
    primes.set(0, false);
    primes.set(1, false);
    primes.set(2, limit, true);
    for (int i = 0; i * i < limit; i++)
    {
        if (primes.get(i))
        {
            for (int j = i * i; j < limit; j += i)
            {
                primes.clear(j);
            }
        }
    }
    return primes;
}

3
นั่นเป็นการใช้ตะแกรง Eratosthenes ที่ดีมาก
David Johnstone

1
มันไม่เพียงพอที่จะวนซ้ำในขณะที่i <= Math.sqrt(limit)อยู่ในวงนอก?
Christoph

1
@David Johnstone No, pi (n) = n / log (n) ประเมินจำนวน primes ต่ำกว่า n ซึ่งไปในทิศทางตรงกันข้าม ฉันดีใจที่คุณพบการประมาณที่ดีกว่านี้มาก
starblue

1
หากคุณยินดีที่จะลบการทวีคูณของ 2 ทั้งหมดในลูปของตัวเองคุณสามารถใช้ j + = 2 * i เป็นการเพิ่มลูปของคุณเพื่อประหยัดรันไทม์เพิ่มเติมและคุณสามารถคำนวณได้ว่าเมื่อใช้บิต shift
Nick Larsen

5
เมื่อแทนที่BitSetด้วยคลาสที่ใช้การแยกตัวประกอบล้อสำหรับ 2, 3 และ 5 จะทำให้เร็วขึ้นเกือบ 3 เท่า
starblue

37

ขอบคุณมากสำหรับทุกคนที่ให้คำตอบที่เป็นประโยชน์ นี่คือการใช้งานวิธีการต่างๆในการค้นหาn primes แรกใน C # สองวิธีแรกเป็นสิ่งที่โพสต์ไว้ที่นี่ (ชื่อผู้โพสต์อยู่ถัดจากชื่อเรื่อง) บางครั้งฉันวางแผนที่จะทำตะแกรงของ Atkin แม้ว่าฉันจะสงสัยว่ามันจะไม่ง่ายเหมือนวิธีการที่นี่ในตอนนี้ หากใครสามารถเห็นวิธีการปรับปรุงวิธีการใด ๆ เหล่านี้ฉันอยากรู้ :-)

วิธีมาตรฐาน ( Peter Smit , jmservera , Rekreativc )

จำนวนเฉพาะแรกคือ 2 เพิ่มสิ่งนี้ในรายการไพรม์ จำนวนเฉพาะถัดไปคือจำนวนถัดไปที่หารด้วยจำนวนใด ๆ ในรายการนี้ไม่ได้

public static List<int> GeneratePrimesNaive(int n)
{
    List<int> primes = new List<int>();
    primes.Add(2);
    int nextPrime = 3;
    while (primes.Count < n)
    {
        int sqrt = (int)Math.Sqrt(nextPrime);
        bool isPrime = true;
        for (int i = 0; (int)primes[i] <= sqrt; i++)
        {
            if (nextPrime % primes[i] == 0)
            {
                isPrime = false;
                break;
            }
        }
        if (isPrime)
        {
            primes.Add(nextPrime);
        }
        nextPrime += 2;
    }
    return primes;
}

สิ่งนี้ได้รับการปรับให้เหมาะสมโดยเฉพาะการทดสอบความสามารถในการหารถึงค่ารากที่สองของจำนวนที่ทดสอบเท่านั้น และทดสอบเฉพาะเลขคี่ นี้สามารถเพิ่มประสิทธิภาพต่อไปโดยการทดสอบเพียงตัวเลขของรูปแบบ6k+[1, 5]หรือ30k+[1, 7, 11, 13, 17, 19, 23, 29]หรืออื่น

ตะแกรงของ Eratosthenes ( starblue )

พบทั้งหมดนี้เฉพาะเพื่อ k เพื่อสร้างรายการของn ตัวแรก primes แรกเราต้องประมาณค่าของnไพรม์ก่อน วิธีการต่อไปนี้ตามที่อธิบายไว้ที่นี่จะทำเช่นนี้

public static int ApproximateNthPrime(int nn)
{
    double n = (double)nn;
    double p;
    if (nn >= 7022)
    {
        p = n * Math.Log(n) + n * (Math.Log(Math.Log(n)) - 0.9385);
    }
    else if (nn >= 6)
    {
        p = n * Math.Log(n) + n * Math.Log(Math.Log(n));
    }
    else if (nn > 0)
    {
        p = new int[] { 2, 3, 5, 7, 11 }[nn - 1];
    }
    else
    {
        p = 0;
    }
    return (int)p;
}

// Find all primes up to and including the limit
public static BitArray SieveOfEratosthenes(int limit)
{
    BitArray bits = new BitArray(limit + 1, true);
    bits[0] = false;
    bits[1] = false;
    for (int i = 0; i * i <= limit; i++)
    {
        if (bits[i])
        {
            for (int j = i * i; j <= limit; j += i)
            {
                bits[j] = false;
            }
        }
    }
    return bits;
}

public static List<int> GeneratePrimesSieveOfEratosthenes(int n)
{
    int limit = ApproximateNthPrime(n);
    BitArray bits = SieveOfEratosthenes(limit);
    List<int> primes = new List<int>();
    for (int i = 0, found = 0; i < limit && found < n; i++)
    {
        if (bits[i])
        {
            primes.Add(i);
            found++;
        }
    }
    return primes;
}

ตะแกรงซันดาราม

ฉันเพิ่งค้นพบตะแกรงนี้เมื่อไม่นานมานี้ แต่สามารถใช้งานได้ค่อนข้างง่าย การใช้งานของฉันไม่เร็วเท่าตะแกรงของ Eratosthenes แต่เร็วกว่าวิธีการไร้เดียงสาอย่างมาก

public static BitArray SieveOfSundaram(int limit)
{
    limit /= 2;
    BitArray bits = new BitArray(limit + 1, true);
    for (int i = 1; 3 * i + 1 < limit; i++)
    {
        for (int j = 1; i + j + 2 * i * j <= limit; j++)
        {
            bits[i + j + 2 * i * j] = false;
        }
    }
    return bits;
}

public static List<int> GeneratePrimesSieveOfSundaram(int n)
{
    int limit = ApproximateNthPrime(n);
    BitArray bits = SieveOfSundaram(limit);
    List<int> primes = new List<int>();
    primes.Add(2);
    for (int i = 1, found = 1; 2 * i + 1 <= limit && found < n; i++)
    {
        if (bits[i])
        {
            primes.Add(2 * i + 1);
            found++;
        }
    }
    return primes;
}

FYI - ฉันต้องเปลี่ยนตัวนับลูปหลักของคุณเป็น "for (int i = 0; i * i <= limit && i * i> 0; i ++)" เพื่อป้องกันการล้น
Jacobs Data Solutions

การใช้งาน Sieve of Sundaram นี้เป็นหนึ่งในไม่กี่ตัวที่ถูกต้อง ส่วนใหญ่ใช้ขอบเขตที่ไม่ถูกต้องสำหรับ i และ j ในขณะที่คำนวณi+j+2*i*jนำไปสู่ผลลัพธ์ที่ไม่ถูกต้อง
jahackbeth

16

กำลังตอบคำถามเก่าอีกครั้ง แต่ฉันสะดุดกับคำถามนั้นขณะเล่นกับ LINQ

รหัสนี้ต้องการ. NET4.0 หรือ. NET3.5 พร้อมส่วนขยายแบบขนาน

public List<int> GeneratePrimes(int n) {
    var r = from i in Enumerable.Range(2, n - 1).AsParallel()
            where Enumerable.Range(1, (int)Math.Sqrt(i)).All(j => j == 1 || i % j != 0)
            select i;
    return r.ToList();
}

1
เหตุใดจึงไม่เป็นคำตอบที่ยอมรับ รหัสที่นี่สั้นกว่าสวยงามกว่าและเร็วกว่ารหัสในคำตอบที่ยอมรับมาก หวังว่าฉันจะโหวตได้มากกว่าหนึ่งครั้ง!
Avrohom Yisroel

9

คุณอยู่บนเส้นทางที่ดี

บางความคิดเห็น

  • primes.Add (3); ทำให้ฟังก์ชันนี้ใช้ไม่ได้กับ number = 1

  • คุณไม่จำเป็นต้องทดสอบการหารด้วย primenumbers ที่ใหญ่กว่าที่กำลังสองของจำนวนที่จะทดสอบ

รหัสที่แนะนำ:

ArrayList generatePrimes(int toGenerate)
{
    ArrayList primes = new ArrayList();

    if(toGenerate > 0) primes.Add(2);

    int curTest = 3;
    while (primes.Count < toGenerate)
    {

        int sqrt = (int) Math.sqrt(curTest);

        bool isPrime = true;
        for (int i = 0; i < primes.Count && primes.get(i) <= sqrt; ++i)
        {
            if (curTest % primes.get(i) == 0)
            {
                isPrime = false;
                break;
            }
        }

        if(isPrime) primes.Add(curTest);

        curTest +=2
    }
    return primes;
}

1
การทดสอบไพรม์ * ไพรม์ <= curTest ในลูปแทนที่จะคำนวณสแควร์รูทล่วงหน้าอาจทำให้เร็วขึ้นและจะทำให้เป็นแบบทั่วไปมากขึ้น (จะใช้ได้กับ bignums ฯลฯ )
yairchu

ทำไมต้องใช้สแควร์รูท พื้นหลังทางคณิตศาสตร์สำหรับตัวเลือกดังกล่าวคืออะไร? ฉันอาจจะโง่แค่หารด้วย 2 เท่านั้น
Luis Filipe

3
เนื่องจากถ้าตัวเลขมีปัจจัยเฉพาะอย่างน้อยหนึ่งในจำนวนนั้นต้องน้อยกว่าหรือเท่ากับรากที่สอง ถ้า a * b = c และ a <= b แล้ว a <= sqrt (c) <= b
David Johnstone

8

คุณควรดูช่วงเวลาที่เป็นไปได้ได้ โดยเฉพาะอย่างยิ่งลองดูอัลกอริทึมแบบสุ่มและการทดสอบเบื้องต้นของมิลเลอร์ - ราบินเบื้องต้นของ

เพื่อความสมบูรณ์คุณสามารถใช้java.math.BigInteger :

public class PrimeGenerator implements Iterator<BigInteger>, Iterable<BigInteger> {

    private BigInteger p = BigInteger.ONE;

    @Override
    public boolean hasNext() {
        return true;
    }

    @Override
    public BigInteger next() {
        p = p.nextProbablePrime();
        return p;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public Iterator<BigInteger> iterator() {
        return this;
    }
}

@Test
public void printPrimes() {
    for (BigInteger p : new PrimeGenerator()) {
        System.out.println(p);
    }
}

2
Miller-Rabbin นั้นเร็วมากและรหัสนั้นง่ายมาก การทำซ้ำให้เพียงพอทำให้มีความน่าเชื่อถือเพียงพอที่จะแข่งขันกับความล้มเหลวของ CPU แบบสุ่มในแง่ของความเป็นไปได้ที่จะเกิดผลบวกผิดพลาด ข้อเสียของอัลกอริทึมคือการทำความเข้าใจว่าเหตุใดจึงใช้งานได้จริงจึงเป็นงานที่ยาก
Brian

6

ไม่ได้มีประสิทธิภาพ แต่อาจอ่านได้มากที่สุด:

public static IEnumerable<int> GeneratePrimes()
{
   return Range(2).Where(candidate => Range(2, (int)Math.Sqrt(candidate)))
                                     .All(divisor => candidate % divisor != 0));
}

กับ:

public static IEnumerable<int> Range(int from, int to = int.MaxValue)
{
   for (int i = from; i <= to; i++) yield return i;
}

อันที่จริงเป็นเพียงรูปแบบของโพสต์บางส่วนที่มีการจัดรูปแบบที่ดีกว่า


5

ลิขสิทธิ์ 2009 โดย St.Wittum 13189 Berlin GERMANY ภายใต้ใบอนุญาต CC-BY-SA https://creativecommons.org/licenses/by-sa/3.0/

วิธีที่ง่าย แต่สง่างามที่สุดในการคำนวณ PRIMES ทั้งหมดจะเป็นวิธีนี้ แต่วิธีนี้ช้าและต้นทุนหน่วยความจำสูงกว่ามากสำหรับตัวเลขที่สูงขึ้นเนื่องจากใช้ฟังก์ชันคณะ (!) ... แต่แสดงให้เห็นถึงรูปแบบของ Wilson Theoreme ในแอปพลิเคชัน สร้างช่วงเวลาทั้งหมดโดยอัลกอริทึมที่ใช้ใน Python

#!/usr/bin/python
f=1 # 0!
p=2 # 1st prime
while True:
    if f%p%2:
        print p
    p+=1
    f*=(p-2)

4

ใช้ตัวสร้างตัวเลขเฉพาะเพื่อสร้าง primes.txt จากนั้น:

class Program
{
    static void Main(string[] args)
    {
        using (StreamReader reader = new StreamReader("primes.txt"))
        {
            foreach (var prime in GetPrimes(10, reader))
            {
                Console.WriteLine(prime);
            }
        }
    }

    public static IEnumerable<short> GetPrimes(short upTo, StreamReader reader)
    {
        int count = 0;
        string line = string.Empty;
        while ((line = reader.ReadLine()) != null && count++ < upTo)
        {
            yield return short.Parse(line);
        }
    }
}

ในกรณีนี้ฉันใช้ Int16 ในลายเซ็นของวิธีการดังนั้นไฟล์ primes.txt ของฉันจึงมีตัวเลขตั้งแต่ 0 ถึง 32767 หากคุณต้องการขยายไปยัง Int32 หรือ Int64 primes.txt ของคุณอาจมีขนาดใหญ่กว่ามาก


3
การอ้างถึง OP: "ฉันไม่สนใจว่าจะใช้วิธีใด (ไร้เดียงสาหรือตะแกรงหรืออย่างอื่น) แต่ฉันต้องการให้มันค่อนข้างสั้นและชัดเจนว่ามันทำงานอย่างไร" ฉันคิดว่าคำตอบของฉันมีความเกี่ยวข้องอย่างสมบูรณ์ ยังเป็นวิธีที่เร็วที่สุด
Darin Dimitrov

14
แม้ว่าเขาจะบอกว่า "ฉันไม่สนใจวิธีการใด ... " ฉันไม่คิดว่ารวมถึง "เปิดรายการราคา" นั่นก็เหมือนกับการตอบคำถาม "วิธีการสร้างคอมพิวเตอร์" โดย "ซื้อคอมพิวเตอร์" -1
stevenvh

8
มันจะเร็วกว่าถ้าคุณเขียนจำนวนเฉพาะในซอร์สโค้ดเองแทนที่จะอ่านจากไฟล์
Daniel Daranas

3
ใช้หน่วยความจำมากไหม มากกว่าการอ่านรายการราคาเต็มเป็นข้อความลงใน ... หน่วยความจำ? คุณรู้หรือไม่ว่าสตริงทำงานอย่างไรใน. net
jmservera

6
รายการของช่วงเวลาเป็นรายการที่ไม่มีที่สิ้นสุด แต่ไม่เปลี่ยนรูปดังนั้นจึงเหมาะสมที่จะใช้รายการที่คำนวณล่วงหน้าจนถึงขอบเขตบนที่เป็นไปได้สำหรับแอปพลิเคชัน ทำไมต้องเสียเวลาเขียนโค้ดที่อาจเป็นปัญหาเมื่อมีรายการสาธารณะที่ถูกต้องซึ่งสามารถใช้เพื่อให้เป็นไปตามข้อกำหนด
AndyM

4

ฉันสามารถเสนอโซลูชัน C # ต่อไปนี้ มันไม่ได้เร็ว แต่มันชัดเจนมากเกี่ยวกับสิ่งที่มันทำ

public static List<Int32> GetPrimes(Int32 limit)
{
    List<Int32> primes = new List<Int32>() { 2 };

    for (int n = 3; n <= limit; n += 2)
    {
        Int32 sqrt = (Int32)Math.Sqrt(n);

        if (primes.TakeWhile(p => p <= sqrt).All(p => n % p != 0))
        {
            primes.Add(n);
        }
    }

    return primes;
}

ฉันทิ้งการตรวจสอบใด ๆ - ถ้าขีด จำกัด เป็นลบหรือน้อยกว่าสอง (ในขณะนี้วิธีการทั้งหมดจะคืนค่าสองเป็นไพรม์เป็นอย่างน้อย) แต่ทั้งหมดนี้แก้ไขได้ง่าย

อัปเดต

ด้วยวิธีการขยายสองวิธีต่อไปนี้

public static void Do<T>(this IEnumerable<T> collection, Action<T> action)
{
    foreach (T item in collection)
    {
        action(item);
    }
}

public static IEnumerable<Int32> Range(Int32 start, Int32 end, Int32 step)
{
    for (int i = start; i < end; i += step)
    }
        yield return i;
    }
}

คุณสามารถเขียนใหม่ได้ดังนี้

public static List<Int32> GetPrimes(Int32 limit)
{
    List<Int32> primes = new List<Int32>() { 2 };

    Range(3, limit, 2)
        .Where(n => primes
            .TakeWhile(p => p <= Math.Sqrt(n))
            .All(p => n % p != 0))
        .Do(n => primes.Add(n));

    return primes;
}

มีประสิทธิภาพน้อยกว่า (เนื่องจากสแควร์รูทมีการประเมินใหม่ค่อนข้างบ่อย) แต่เป็นโค้ดที่สะอาดกว่า เป็นไปได้ที่จะเขียนโค้ดใหม่เพื่อแจกแจงช่วงเวลาอย่างเฉื่อยชา แต่จะทำให้โค้ดไม่เป็นระเบียบ


ฉันเกือบจะเป็นบวกว่าการคำนวณของรากที่สองถูกปรับให้เหมาะสมโดยคอมไพเลอร์ JIT (เมื่อคอมไพล์โดยเปิดใช้งานการปรับให้เหมาะสม) คุณต้องตรวจสอบสิ่งนี้โดยการตรวจสอบชุดประกอบที่สร้างขึ้น (IL ได้รับการปรับให้เหมาะสมเพียงบางส่วนและไม่มีที่ไหนเลยใกล้กับการเพิ่มประสิทธิภาพที่ดำเนินการโดยคอมไพเลอร์ JIT วันของการยกลูปและการเพิ่มประสิทธิภาพขนาดเล็กอื่น ๆ สิ้นสุดลงในความเป็นจริงบางครั้งพยายามที่จะ การชิงไหวชิงพริบ JIT สามารถทำให้โค้ดของคุณช้าลงได้
Dave Black

4

นี่คือการใช้งานSieve of Eratosthenesใน C #:

    IEnumerable<int> GeneratePrimes(int n)
    {
        var values = new Numbers[n];

        values[0] = Numbers.Prime;
        values[1] = Numbers.Prime;

        for (int outer = 2; outer != -1; outer = FirstUnset(values, outer))
        {
            values[outer] = Numbers.Prime;

            for (int inner = outer * 2; inner < values.Length; inner += outer)
                values[inner] = Numbers.Composite;
        }

        for (int i = 2; i < values.Length; i++)
        {
            if (values[i] == Numbers.Prime)
                yield return i;
        }
    }

    int FirstUnset(Numbers[] values, int last)
    {
        for (int i = last; i < values.Length; i++)
            if (values[i] == Numbers.Unset)
                return i;

        return -1;
    }

    enum Numbers
    {
        Unset,
        Prime,
        Composite
    }

ฉันจะใช้บูลแทน enum ...
Letterman

3

การใช้อัลกอริทึมเดียวกันของคุณคุณสามารถทำได้สั้นกว่านี้เล็กน้อย:

List<int> primes=new List<int>(new int[]{2,3});
for (int n = 5; primes.Count< numberToGenerate; n+=2)
{
  bool isPrime = true;
  foreach (int prime in primes)
  {
    if (n % prime == 0)
    {
      isPrime = false;
      break;
    }
  }
  if (isPrime)
    primes.Add(n);
}

3

ฉันรู้ว่าคุณขอวิธีแก้ปัญหาที่ไม่ใช่ Haskell แต่ฉันรวมสิ่งนี้ไว้ที่นี่เพราะเกี่ยวข้องกับคำถามและ Haskell ก็สวยงามสำหรับสิ่งประเภทนี้

module Prime where

primes :: [Integer]
primes = 2:3:primes'
  where
    -- Every prime number other than 2 and 3 must be of the form 6k + 1 or 
    -- 6k + 5. Note we exclude 1 from the candidates and mark the next one as
    -- prime (6*0+5 == 5) to start the recursion.
    1:p:candidates = [6*k+r | k <- [0..], r <- [1,5]]
    primes'        = p : filter isPrime candidates
    isPrime n      = all (not . divides n) $ takeWhile (\p -> p*p <= n) primes'
    divides n p    = n `mod` p == 0

ใช่ฉันเป็นแฟนตัวยงของ Haskell ด้วย (ฉันแค่หวังว่าฉันจะรู้ดีกว่านี้)
David Johnstone

3

ฉันเขียนการใช้งาน Eratosthenes อย่างง่ายใน c # โดยใช้ LINQ

น่าเสียดายที่ LINQ ไม่มีลำดับ ints ที่ไม่มีที่สิ้นสุดดังนั้นคุณต้องใช้ int.MaxValue :(

ฉันต้องแคชในการพิมพ์ sqrt ที่ไม่เป็นหนึ่งเดียวเพื่อหลีกเลี่ยงการคำนวณสำหรับแต่ละไพรม์แคช (ดูน่าเกลียดเล็กน้อย)

ฉันใช้รายการของช่วงเวลาก่อนหน้าจนถึง sqrt ของผู้สมัคร

cache.TakeWhile(c => c <= candidate.Sqrt)

และตรวจสอบทุก Int เริ่มต้นจาก 2 เทียบกับมัน

.Any(cachedPrime => candidate.Current % cachedPrime == 0)

นี่คือรหัส:

static IEnumerable<int> Primes(int count)
{
    return Primes().Take(count);
}

static IEnumerable<int> Primes()
{
    List<int> cache = new List<int>();

    var primes = Enumerable.Range(2, int.MaxValue - 2).Select(candidate => new 
    {
        Sqrt = (int)Math.Sqrt(candidate), // caching sqrt for performance
        Current = candidate
    }).Where(candidate => !cache.TakeWhile(c => c <= candidate.Sqrt)
            .Any(cachedPrime => candidate.Current % cachedPrime == 0))
            .Select(p => p.Current);

    foreach (var prime in primes)
    {
        cache.Add(prime);
        yield return prime;
    }
}

การเพิ่มประสิทธิภาพอีกวิธีหนึ่งคือการหลีกเลี่ยงการตรวจสอบเลขคู่และส่งกลับเพียง 2 ก่อนสร้างรายการ วิธีนี้หากวิธีการโทรขอเพียง 1 ไพรม์มันจะหลีกเลี่ยงความยุ่งเหยิงทั้งหมด:

static IEnumerable<int> Primes()
{
    yield return 2;
    List<int> cache = new List<int>() { 2 };

    var primes = Enumerable.Range(3, int.MaxValue - 3)
        .Where(candidate => candidate % 2 != 0)
        .Select(candidate => new
    {
        Sqrt = (int)Math.Sqrt(candidate), // caching sqrt for performance
        Current = candidate
    }).Where(candidate => !cache.TakeWhile(c => c <= candidate.Sqrt)
            .Any(cachedPrime => candidate.Current % cachedPrime == 0))
            .Select(p => p.Current);

    foreach (var prime in primes)
    {
        cache.Add(prime);
        yield return prime;
    }
}

1
ฉันหวังว่าฉันจะรู้จัก LINQ มากพอที่จะชื่นชมและเข้าใจคำตอบนี้ได้ดีขึ้น :-) นอกจากนี้ฉันมีความรู้สึกว่านี่ไม่ใช่การใช้ตะแกรงเอราโตสเธเนสและมันทำงานในแนวความคิดเหมือนกับฟังก์ชันเดิมของฉัน (ค้นหาต่อไป จำนวนที่หารด้วยไพรม์ที่พบก่อนหน้านี้ไม่ได้)
David Johnstone

ใช่ แต่ "หาจำนวนถัดไปที่หารด้วยไพรม์ที่พบก่อนหน้านี้ไม่ได้ (น้อยกว่าจำนวน)" มีแนวคิดคล้ายกับตะแกรงเอราทอสเทนีส หากคุณต้องการฉันสามารถปรับโครงสร้างใหม่เล็กน้อยเพื่อให้อ่านง่ายขึ้นแม้ว่าคุณจะไม่คุ้นเคยกับ LINQ ก็ตาม คุณคุ้นเคยกับตัวทำซ้ำหรือไม่?
Maghis

สิ่งที่ฉันชอบของแนวทางนี้คือไพรม์ถัดไปจะถูกคำนวณเมื่อผู้โทรถามดังนั้นสิ่งต่างๆเช่น "รับ n primes แรก" หรือ "ใช้
ไพรม์

1
ขอบคุณ แต่ฉันสามารถเข้าใจได้ว่ามากพอที่จะรู้ว่ามันทำอะไร :-) ฉันชอบการประเมินแบบขี้เกียจ แต่ฉันก็ยังไม่เรียกสิ่งนี้ว่าการใช้ตะแกรงเอราทอสเทนีส
David Johnstone

1

เพื่อให้สวยงามยิ่งขึ้นคุณควรปรับเปลี่ยนการทดสอบ IsPrime ของคุณใหม่เป็นวิธีการแยกต่างหากและจัดการกับการวนซ้ำและการเพิ่มที่นอกเหนือจากนั้น


1

ฉันทำใน Java โดยใช้ไลบรารีที่ใช้งานได้ที่ฉันเขียน แต่เนื่องจากไลบรารีของฉันใช้แนวคิดเดียวกันกับการแจงนับฉันมั่นใจว่าโค้ดสามารถปรับเปลี่ยนได้:

Iterable<Integer> numbers = new Range(1, 100);
Iterable<Integer> primes = numbers.inject(numbers, new Functions.Injecter<Iterable<Integer>, Integer>()
{
    public Iterable<Integer> call(Iterable<Integer> numbers, final Integer number) throws Exception
    {
        // We don't test for 1 which is implicit
        if ( number <= 1 )
        {
            return numbers;
        }
        // Only keep in numbers those that do not divide by number
        return numbers.reject(new Functions.Predicate1<Integer>()
        {
            public Boolean call(Integer n) throws Exception
            {
                return n > number && n % number == 0;
            }
        });
    }
});

1

นี่เป็นสิ่งที่สง่างามที่สุดที่ฉันคิดได้จากการบอกกล่าวสั้น ๆ

ArrayList generatePrimes(int numberToGenerate)
{
    ArrayList rez = new ArrayList();

    rez.Add(2);
    rez.Add(3);

    for(int i = 5; rez.Count <= numberToGenerate; i+=2)
    {
        bool prime = true;
        for (int j = 2; j < Math.Sqrt(i); j++)
        {
            if (i % j == 0)
            {
                    prime = false;
                    break;
            }
        }
        if (prime) rez.Add(i);
    }

    return rez;
}

หวังว่านี่จะช่วยให้คุณมีความคิด ฉันแน่ใจว่าสิ่งนี้สามารถปรับให้เหมาะสมได้อย่างไรก็ตามควรให้ความคิดว่าเวอร์ชันของคุณจะทำให้สง่างามมากขึ้นได้อย่างไร

แก้ไข:ตามที่ระบุไว้ในความคิดเห็นอัลกอริทึมนี้ส่งคืนค่าที่ไม่ถูกต้องสำหรับ numberToGenerate <2 ฉันแค่อยากจะชี้ให้เห็นว่าฉันไม่ได้พยายามโพสต์วิธีการที่ยอดเยี่ยมให้เขาในการสร้างจำนวนเฉพาะ (ดูคำตอบของอองรี) ฉันชี้ให้เห็นอย่างชัดเจนว่าวิธีการของเขาจะทำให้สง่างามขึ้น


3
อันนี้ส่งคืนผลลัพธ์ผิดสำหรับ numberToGenerate <2
Peter Smit

นี่เป็นเรื่องจริง แต่ฉันไม่ได้ออกแบบอัลกอริทึมฉันแค่แสดงให้เขาเห็นว่าวิธีการของเขาสามารถทำให้สวยขึ้นได้อย่างไร ดังนั้นเวอร์ชันนี้จึงผิดพอ ๆ กันกับคำถามเปิด
David Božjak

1
มันไม่ได้เกิดขึ้นกับฉันว่ามันเสียสำหรับ n = 1 ฉันเปลี่ยนคำถามเล็กน้อยเพื่อให้ฟังก์ชันใช้งานได้เฉพาะสำหรับ n> 1 :-)
David Johnstone

นี่ยอมรับว่ากำลังสองของไพรม์เป็นจำนวนเฉพาะ
Will Ness

1

การใช้การเขียนโปรแกรมบนสตรีมในFunctional Javaฉันได้สิ่งต่อไปนี้ โดยพื้นฐานแล้วประเภทNaturalคือ a BigInteger> = 0

public static Stream<Natural> sieve(final Stream<Natural> xs)
{ return cons(xs.head(), new P1<Stream<Natural>>()
  { public Stream<Natural> _1()
    { return sieve(xs.tail()._1()
                   .filter($(naturalOrd.equal().eq(ZERO))
                           .o(mod.f(xs.head())))); }}); }

public static final Stream<Natural> primes
  = sieve(forever(naturalEnumerator, natural(2).some()));

ตอนนี้คุณมีค่าที่คุณสามารถพกพาไปได้ซึ่งเป็นกระแสของช่วงเวลาที่ไม่มีที่สิ้นสุด คุณสามารถทำสิ่งต่างๆดังนี้

// Take the first n primes
Stream<Natural> nprimes = primes.take(n);

// Get the millionth prime
Natural mprime = primes.index(1000000);

// Get all primes less than n
Stream<Natural> pltn = primes.takeWhile(naturalOrd.lessThan(n));

คำอธิบายของตะแกรง:

  1. สมมติว่าหมายเลขแรกในสตรีมอาร์กิวเมนต์เป็นจำนวนเฉพาะและวางไว้ที่ด้านหน้าของสตรีมส่งคืน ส่วนที่เหลือของสตรีมส่งคืนเป็นการคำนวณที่จะสร้างขึ้นเมื่อถูกร้องขอเท่านั้น
  2. หากมีคนขอสตรีมที่เหลือให้เรียกใช้ตะแกรงที่ส่วนที่เหลือของสตรีมอาร์กิวเมนต์โดยกรองตัวเลขที่หารด้วยจำนวนแรกได้ (ส่วนที่เหลือของการหารเป็นศูนย์)

คุณต้องมีการนำเข้าดังต่อไปนี้:

import fj.P1;
import static fj.FW.$;
import static fj.data.Enumerator.naturalEnumerator;
import fj.data.Natural;
import static fj.data.Natural.*;
import fj.data.Stream;
import static fj.data.Stream.*;
import static fj.pre.Ord.naturalOrd;

1

โดยส่วนตัวฉันคิดว่านี่เป็นการใช้งาน (Java) ที่สั้นและสะอาด:

static ArrayList<Integer> getPrimes(int numPrimes) {
    ArrayList<Integer> primes = new ArrayList<Integer>(numPrimes);
    int n = 2;
    while (primes.size() < numPrimes) {
        while (!isPrime(n)) { n++; }
        primes.add(n);
        n++;
    }
    return primes;
}

static boolean isPrime(int n) {
    if (n < 2) { return false; }
    if (n == 2) { return true; }
    if (n % 2 == 0) { return false; }
    int d = 3;
    while (d * d <= n) {
        if (n % d == 0) { return false; }
        d += 2;
    }
    return true;
}

1

ลองใช้ LINQ Query นี้จะสร้างจำนวนเฉพาะตามที่คุณคาดไว้

        var NoOfPrimes= 5;
        var GeneratedPrime = Enumerable.Range(1, int.MaxValue)
          .Where(x =>
            {
                 return (x==1)? false:
                        !Enumerable.Range(1, (int)Math.Sqrt(x))
                        .Any(z => (x % z == 0 && x != z && z != 1));
            }).Select(no => no).TakeWhile((val, idx) => idx <= NoOfPrimes-1).ToList();

1
// Create a test range
IEnumerable<int> range = Enumerable.Range(3, 50 - 3);

// Sequential prime number generator
var primes_ = from n in range
     let w = (int)Math.Sqrt(n)
     where Enumerable.Range(2, w).All((i) => n % i > 0)
     select n;

// Note sequence of output:
// 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
foreach (var p in primes_)
    Trace.Write(p + ", ");
Trace.WriteLine("");

0

นี่คือตัวอย่างโค้ด python ที่พิมพ์ผลรวมของ primes ทั้งหมดที่ต่ำกว่าสองล้าน:

from math import *

limit = 2000000
sievebound = (limit - 1) / 2
# sieve only odd numbers to save memory
# the ith element corresponds to the odd number 2*i+1
sieve = [False for n in xrange(1, sievebound + 1)]
crosslimit = (int(ceil(sqrt(limit))) - 1) / 2
for i in xrange(1, crosslimit):
    if not sieve[i]:
        # if p == 2*i + 1, then
        #   p**2 == 4*(i**2) + 4*i + 1
        #        == 2*i * (i + 1)
        for j in xrange(2*i * (i + 1), sievebound, 2*i + 1):
            sieve[j] = True
sum = 2
for i in xrange(1, sievebound):
    if not sieve[i]:
        sum = sum + (2*i+1)
print sum

0

วิธีที่ง่ายที่สุดคือการลองผิดลองถูก: คุณลองดูว่าตัวเลขใด ๆ ระหว่าง 2 ถึง n-1 หารตัวเลือกเฉพาะ n
ทางลัดแรกเป็นแน่นอน a) คุณต้องตรวจสอบเลขคี่เท่านั้นและ b) คุณตรวจสอบตัวแบ่งได้สูงสุด sqrt (n) เท่านั้น

ในกรณีของคุณที่คุณสร้าง primes ก่อนหน้านี้ทั้งหมดในกระบวนการด้วยคุณจะต้องตรวจสอบว่าไพรม์ใดในรายการของคุณสูงสุด sqrt (n) หาร n
ควรเร็วที่สุดที่คุณจะได้รับเงินของคุณ :-)

แก้ไข
ตกลงรหัสที่คุณขอ แต่ฉันเตือนคุณ :-) นี่คือรหัส Delphi ที่รวดเร็วและสกปรก 5 นาที:

procedure TForm1.Button1Click(Sender: TObject);
const
  N = 100;
var
  PrimeList: TList;
  I, J, SqrtP: Integer;
  Divides: Boolean;
begin
  PrimeList := TList.Create;
  for I := 2 to N do begin
    SqrtP := Ceil(Sqrt(I));
    J := 0;
    Divides := False;
    while (not Divides) and (J < PrimeList.Count) 
                        and (Integer(PrimeList[J]) <= SqrtP) do begin
      Divides := ( I mod Integer(PrimeList[J]) = 0 );
      inc(J);
    end;
    if not Divides then
      PrimeList.Add(Pointer(I));
  end;
  // display results
  for I := 0 to PrimeList.Count - 1 do
    ListBox1.Items.Add(IntToStr(Integer(PrimeList[I])));
  PrimeList.Free;
end;

1
และคุณแสดงสิ่งนี้ในรหัสได้อย่างไร? :-)
David Johnstone

0

ในการหาจำนวนเฉพาะ 100 ตัวแรกสามารถพิจารณาโค้ดจาวาต่อไปนี้ได้

int num = 2;
int i, count;
int nPrimeCount = 0;
int primeCount = 0;

    do
    {

        for (i = 2; i <num; i++)
        {

             int n = num % i;

             if (n == 0) {

             nPrimeCount++;
         //  System.out.println(nPrimeCount + " " + "Non-Prime Number is: " + num);

             num++;
             break;

             }
       }

                if (i == num) {

                    primeCount++;

                    System.out.println(primeCount + " " + "Prime number is: " + num);
                    num++;
                }


     }while (primeCount<100);

0

ฉันได้รับสิ่งนี้จากการอ่าน "Sieve of Atkin" ใน Wikki เป็นครั้งแรกบวกกับความคิดก่อนหน้านี้ที่ฉันเคยให้ไว้ - ฉันใช้เวลาส่วนใหญ่ในการเขียนโค้ดตั้งแต่เริ่มต้นและได้รับความสนใจอย่างมากจากคนที่วิจารณ์การเข้ารหัสที่มีลักษณะคล้ายคอมไพเลอร์และหนาแน่นมาก style + ฉันยังไม่ได้พยายามรันโค้ดเป็นครั้งแรก ... กระบวนทัศน์หลายอย่างที่ฉันได้เรียนรู้ที่จะใช้อยู่ที่นี่เพียงแค่อ่านและร้องไห้รับสิ่งที่คุณทำได้

อย่าลืมทดสอบทั้งหมดนี้จริงๆก่อนการใช้งานอย่าแสดงให้ใครเห็น - เป็นการอ่านและพิจารณาแนวคิด ฉันต้องการให้เครื่องมือเบื้องต้นทำงานได้ดังนั้นนี่คือจุดเริ่มต้นทุกครั้งที่ฉันต้องทำงานให้ได้

รับคอมไพล์ที่สะอาดแล้วเริ่มกำจัดสิ่งที่มีข้อบกพร่อง - ฉันมีโค้ดที่ใช้งานได้เกือบ 108 ล้านครั้งทำแบบนี้ ... ใช้สิ่งที่คุณทำได้

ฉันจะทำงานในเวอร์ชันของฉันในวันพรุ่งนี้

package demo;
// This code is a discussion of an opinion in a technical forum.
// It's use as a basis for further work is not prohibited.
import java.util.Arrays;
import java.util.HashSet;
import java.util.ArrayList;
import java.security.GeneralSecurityException;

/**
 * May we start by ignores any numbers divisible by two, three, or five
 * and eliminate from algorithm 3, 5, 7, 11, 13, 17, 19 completely - as
 * these may be done by hand. Then, with some thought we can completely
 * prove to certainty that no number larger than square-root the number
 * can possibly be a candidate prime.
 */

public class PrimeGenerator<T>
{
    //
    Integer HOW_MANY;
    HashSet<Integer>hashSet=new HashSet<Integer>();
    static final java.lang.String LINE_SEPARATOR
       =
       new java.lang.String(java.lang.System.getProperty("line.separator"));//
    //
    PrimeGenerator(Integer howMany) throws GeneralSecurityException
    {
        if(howMany.intValue() < 20)
        {
            throw new GeneralSecurityException("I'm insecure.");
        }
        else
        {
            this.HOW_MANY=howMany;
        }
    }
    // Let us then take from the rich literature readily 
    // available on primes and discount
    // time-wasters to the extent possible, utilizing the modulo operator to obtain some
    // faster operations.
    //
    // Numbers with modulo sixty remainder in these lists are known to be composite.
    //
    final HashSet<Integer> fillArray() throws GeneralSecurityException
    {
        // All numbers with modulo-sixty remainder in this list are not prime.
        int[]list1=new int[]{0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,
        32,34,36,38,40,42,44,46,48,50,52,54,56,58};        //
        for(int nextInt:list1)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list1");//
            }
        }
        // All numbers with modulo-sixty remainder in this list are  are
        // divisible by three and not prime.
        int[]list2=new int[]{3,9,15,21,27,33,39,45,51,57};
        //
        for(int nextInt:list2)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list2");//
            }
        }
        // All numbers with modulo-sixty remainder in this list are
        // divisible by five and not prime. not prime.
        int[]list3=new int[]{5,25,35,55};
        //
        for(int nextInt:list3)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list3");//
            }
        }
        // All numbers with modulo-sixty remainder in
        // this list have a modulo-four remainder of 1.
        // What that means, I have neither clue nor guess - I got all this from
        int[]list4=new int[]{1,13,17,29,37,41,49,53};
        //
        for(int nextInt:list4)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list4");//
            }
        }
        Integer lowerBound=new Integer(19);// duh
        Double upperStartingPoint=new Double(Math.ceil(Math.sqrt(Integer.MAX_VALUE)));//
        int upperBound=upperStartingPoint.intValue();//
        HashSet<Integer> resultSet=new HashSet<Integer>();
        // use a loop.
        do
        {
            // One of those one liners, whole program here:
            int aModulo=upperBound % 60;
            if(this.hashSet.contains(new Integer(aModulo)))
            {
                continue;
            }
            else
            {
                resultSet.add(new Integer(aModulo));//
            }
        }
        while(--upperBound > 20);
        // this as an operator here is useful later in your work.
        return resultSet;
    }
    // Test harness ....
    public static void main(java.lang.String[] args)
    {
        return;
    }
}
//eof

0

ลองใช้รหัสนี้

protected bool isPrimeNubmer(int n)
    {
        if (n % 2 == 0)
            return false;
        else
        {
            int j = 3;
            int k = (n + 1) / 2 ;

            while (j <= k)
            {
                if (n % j == 0)
                    return false;
                j = j + 2;
            }
            return true;
        }
    }
    protected void btn_primeNumbers_Click(object sender, EventArgs e)
    {
        string time = "";
        lbl_message.Text = string.Empty;
        int num;

        StringBuilder builder = new StringBuilder();

        builder.Append("<table><tr>");
        if (int.TryParse(tb_number.Text, out num))
        {
            if (num < 0)
                lbl_message.Text = "Please enter a number greater than or equal to 0.";
            else
            {
                int count = 1;
                int number = 0;
                int cols = 11;

                var watch = Stopwatch.StartNew();

                while (count <= num)
                {
                    if (isPrimeNubmer(number))
                    {
                        if (cols > 0)
                        {
                            builder.Append("<td>" + count + " - " + number + "</td>");
                        }
                        else
                        {
                            builder.Append("</tr><tr><td>" + count + " - " + number + "</td>");
                            cols = 11;
                        }
                        count++;
                        number++;
                        cols--;
                    }
                    else
                        number++;
                }
                builder.Append("</table>");
                watch.Stop();
                var elapsedms = watch.ElapsedMilliseconds;
                double seconds = elapsedms / 1000;
                time = seconds.ToString();
                lbl_message.Text = builder.ToString();
                lbl_time.Text = time;
            }
        }
        else
            lbl_message.Text = "Please enter a numberic number.";

        lbl_time.Text = time;

        tb_number.Text = "";
        tb_number.Focus();
    }

นี่คือรหัส aspx

<form id="form1" runat="server">
    <div>
        <p>Please enter a number: <asp:TextBox ID="tb_number" runat="server"></asp:TextBox></p>

        <p><asp:Button ID="btn_primeNumbers" runat="server" Text="Show Prime Numbers" OnClick="btn_primeNumbers_Click" />
        </p>
        <p><asp:Label ID="lbl_time" runat="server"></asp:Label></p>
        <p><asp:Label ID="lbl_message" runat="server"></asp:Label></p>
    </div>
</form>

ผลลัพธ์: 10,000 Prime Numbers ในเวลาน้อยกว่าหนึ่งวินาที

100000 Prime Numbers ใน 63 วินาที

สกรีนช็อตของ Prime Numbers 100 ตัวแรก ใส่คำอธิบายภาพที่นี่


1
ลองดูแล้วฉันสามารถวัดประสิทธิภาพและการนำเสนอผลงานได้: โปรดโต้แย้งความสง่างามของมัน
greybeard

การจัดแต่งทรงผมเป็นเพียงส่วนเสริม ให้ฉันพูดถึงอัลกอริทึมสำหรับการส่งคืนจริง / เท็จเป็นจำนวนเฉพาะ n% 2 จะกำจัดครึ่งหนึ่งของตัวเลขเนื่องจากเลขคู่หารด้วย 2 ได้เสมอในอีกรหัสหนึ่งฉันหารด้วยจำนวนคี่เท่านั้นโดยเพิ่มหารด้วยสองได้ (ดังนั้นหารคี่ถัดไปก็เป็นเลขคี่ด้วย) ไม่เกินครึ่งหนึ่งของจำนวนนั้นซึ่งเป็นจำนวนเฉพาะ หรือไม่. ทำไมครึ่งหนึ่งถึงไม่เสียเวลาเพราะมันจะให้เราตอบเป็นเศษส่วน
riz

log10 (63) ~ = 1.8 นั่นคือข้อมูลของคุณแสดงอัตราการเติบโตของ n ^ 1.8 มันช้ามาก ตะแกรงที่เหมาะสมที่สุดของการใช้งาน Eratosthenes exibit ~ n ^ 1.01..1.05; การแบ่งการทดลองที่เหมาะสมที่สุด ~ n ^ 1.35..1.45 คุณisPrimeNubmerใช้ส่วนไตรภาคีที่ไม่เหมาะสม asymptotycs ของมันจะแย่ลงประมาณ n ^ 2 (หรือสูงกว่านั้น) เมื่อคุณพยายามสร้าง primes ให้มากขึ้น
Will Ness
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.