ค้นหานายกที่บอบบางที่สุด


21

พิจารณาฟังก์ชั่นRemove(n, startIndex, count)ที่เอาcountตัวเลขจากหมายเลขที่เริ่มต้นจากหลักที่ตำแหน่งn startIndexตัวอย่าง:

Remove(1234, 1, 1) = 234
Remove(123456, 2, 3) = 156
Remove(1507, 1, 2) = 07 = 7
Remove(1234, 1, 4) = 0

เราจะเรียกหมายเลขเฉพาะ X ที่เปราะบางหากRemoveการดำเนินการที่เป็นไปได้ทั้งหมดทำให้ไม่สำคัญ ตัวอย่างเช่น 80651 เป็นช่วงเวลาที่บอบบางเพราะตัวเลขทั้งหมดต่อไปนี้ไม่ได้เป็นจำนวนเฉพาะ:

651, 51, 1, 0, 8651, 851, 81, 8, 8051, 801, 80, 8061, 806, 8065

เป้าหมาย

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

คะแนนเป็นจำนวนเฉพาะที่เปราะบางซึ่งโปรแกรมของคุณพบ ในกรณีที่เสมอกันการส่งก่อนหน้านี้จะชนะ

กฎระเบียบ

  • คุณสามารถใช้ภาษาใดก็ได้และห้องสมุดบุคคลที่สามใด ๆ
  • คุณเรียกใช้โปรแกรมบนฮาร์ดแวร์ของคุณเอง
  • คุณอาจใช้การทดสอบความน่าจะเป็นแบบดั้งเดิม
  • ทุกอย่างอยู่ในฐาน 10

รายการชั้นนำ

  • 6629 หลักโดย Qualtagh (Java)
  • 5048 หลักโดย Emil (Python 2)
  • 2268 หลักโดย Jakube (Python 2)

แก้ไข:ฉันได้เพิ่มคำตอบของฉันเอง

  • 28164 หลักโดย Suboptimus Prime ตามอัลกอริทึมของ Qualtagh (C #)

5
แม้ว่าฉันจะไม่ได้รหัสยากคำตอบฉันสามารถเริ่มค้นหาในจุดที่ใกล้กับนายกเปราะบางที่มีขนาดใหญ่มาก เห็นได้ชัดว่าไม่มีใครต้องการที่จะเริ่มค้นหาที่ 1 มีอะไรหยุดฉันจากการทำเช่นนี้? ฉันจะเริ่มต้นการค้นหาได้ใกล้แค่ไหนก่อนที่ฉันจะถูกเรียกให้ออกคำตอบที่เข้ารหัสยาก? ฉันรักการท้าทายตามวิธี
Rainbolt

2
@SuboptimusPrime คุณสามารถลบการ จำกัด เวลาออกไปโดยสิ้นเชิงเพราะฉันเชื่อว่าในบางจุดที่จะหายากมาก (คล้ายกับcodegolf.stackexchange.com/questions/41021/… )
Martin Ender


7
คุณยังคงเสียเปรียบผู้ที่มีคอมพิวเตอร์ช้าลง
John Dvorak

11
ฉันใช้เวลานานอย่างน่าละอายที่จะรู้ว่า "เขียนโปรแกรมที่พบว่ามีความเปราะบางที่ใหญ่ที่สุด" ไม่ได้หมายความว่า "มีความเปราะบางที่ใหญ่ที่สุดอยู่แล้วเขียนโปรแกรมที่พบมัน" ฉันเดาว่าฉันทำ Project Euler มากเกินไป :-P
ruakh

คำตอบ:


9

ชวา - 3144 3322 6629 หลัก

6 0{3314} 8969999

6 0{6623} 49099

การแก้ปัญหานี้จะขึ้นอยู่กับคำตอบของ FryAmTheEggman

  1. ตัวเลขสุดท้ายคือ 1 หรือ 9
  2. หากตัวเลขหลักสุดท้ายคือ 1 ดังนั้นตัวเลขก่อนหน้าคือ 0, 8 หรือ 9
  3. หากตัวเลขหลักสุดท้ายคือ 9 ดังนั้นตัวเลขก่อนหน้านี้คือ 0, 4, 6 หรือ 9
  4. ...

เกิดอะไรขึ้นถ้าเราขุดลึกลงไป?

มันกลายเป็นโครงสร้างต้นไม้:

                        S
             -----------------------
             1                     9
    ------------------         ----------------
    0           8    9         0    4    6    9
---------     -----
0   8   9      ...

ลองเรียกหมายเลขคอมโพสิต R ขวาถ้า R และจุดสิ้นสุดทั้งหมดประกอบกัน

เราจะวนซ้ำหมายเลขประกอบที่ถูกต้องทั้งหมดอย่างแรก, 1, 9, 01, 81, 91, 09, 49, 69, 99, 001, 801, 901 เป็นต้น

หมายเลขที่ขึ้นต้นด้วยศูนย์จะไม่ถูกตรวจสอบสำหรับอันดับแรก แต่จำเป็นต้องสร้างตัวเลขเพิ่มเติม

เราจะค้นหาหมายเลขเป้าหมาย N ในรูปแบบ X00 ... 00R โดยที่ X คือหนึ่งใน 4, 6, 8 หรือ 9 และ R เป็นคอมโพสิตที่ถูกต้อง X ไม่สามารถเป็นเลิศได้ X ไม่สามารถเป็น 0 และ X ไม่สามารถเป็น 1 เพราะถ้า R ลงท้ายด้วย 1 หรือ 9 ดังนั้น N จะมี 11 หรือ 19

ถ้า XR มีจำนวนเฉพาะหลังจากการดำเนินการ "ลบ" ดังนั้น XYR จะมีตัวเลขเหล่านั้นสำหรับ Y ใด ๆ ดังนั้นเราไม่ควรสำรวจกิ่งที่เริ่มต้นจาก R

ให้ X เป็นค่าคงที่พูด 6

pseudocode:

X = 6;
for ( String R : breadth-first-traverse-of-all-right-composites ) {
  if ( R ends with 1 or 9 ) {
    if ( remove( X + R, i, j ) is composite for all i and j ) {
      for ( String zeros = ""; zeros.length() < LIMIT; zeros += "0" ) {
        if ( X + zeros + R is prime ) {
          // At this step these conditions hold:
          // 1. X + 0...0 is composite.
          // 2. 0...0 + R = R is composite.
          // 3. X + 0...0 + R is composite if 0...0 is shorter than zeros.
          suits = true;
          for ( E : all R endings )
            if ( X + zeros + E is prime )
              suits = false;
          if ( suits )
            print R + " is fragile prime";
          break; // try another R
                 // because ( X + zeros + 0...0 + R )
                 // would contain prime ( X + zeros + R ).
        }
      }
    }
  }
}

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

รหัสจริงค่อนข้างละเอียดและสามารถพบได้ที่นี่

การทดสอบแบบดั้งเดิมสำหรับตัวเลขในระยะยาวนั้นดำเนินการโดยตัวแปรที่กำหนดขึ้นของการทดสอบมิลเลอร์ สำหรับหมายเลข BigInteger แผนกทดลองจะดำเนินการก่อนแล้วจึงทดสอบ BailliePSW มันอาจเป็นไปได้ แต่ค่อนข้างแน่นอน และเร็วกว่าการทดสอบ Miller-Rabin (เราควรทำซ้ำหลาย ๆ ครั้งสำหรับตัวเลขขนาดใหญ่ใน Miller-Rabin เพื่อให้ได้ความแม่นยำที่เพียงพอ)

แก้ไข:ความพยายามครั้งแรกไม่ถูกต้อง เราควรเพิกเฉยต่อสาขาที่ขึ้นต้นด้วย R หาก X0 ... 0R เป็นจำนวนเฉพาะ จากนั้น X0 ... 0YR จะไม่แตกหักง่าย ดังนั้นจึงมีการเพิ่มการตรวจสอบเพิ่มเติม วิธีนี้ดูเหมือนจะถูกต้อง

แก้ไข 2:เพิ่มการเพิ่มประสิทธิภาพ ถ้า (X + R) หารด้วย 3 ดังนั้น (X + zeros + R) ก็หารด้วย 3 ดังนั้น (X + zeros + R) จึงไม่สามารถเป็นนายกในกรณีนี้และอาจข้าม R นั้นได้

แก้ไข 3:ไม่จำเป็นต้องข้ามตัวเลขหลักหากไม่อยู่ในตำแหน่งสุดท้ายหรือตำแหน่งแรก ดังนั้นตอนจบเช่น 21 หรือ 51 ก็โอเค แต่มันไม่เปลี่ยนแปลงอะไรมาก

สรุป:

  1. คำตอบสุดท้ายของฉันคือการตรวจสอบว่าเปราะบางเป็นเวลา 100 นาที การค้นหาคำตอบ (ตรวจสอบตัวแปรก่อนหน้าทั้งหมด) ใช้เวลาประมาณ 15 นาที ใช่มันไม่มีเหตุผลที่จะ จำกัด เวลาในการค้นหา (เราสามารถเริ่มค้นหาจากหมายเลขเป้าหมายดังนั้นเวลาจะเป็นศูนย์) แต่มันอาจมีความหมายในการ จำกัด เวลาตรวจสอบเช่นเดียวกับในคำถามนี้
  2. คำตอบ 60 ... 049099 มีตัวเลข 4 หลักอยู่ตรงกลาง หากการดำเนินการ "ลบ" สัมผัสมันจำนวนจะกลายเป็นหารด้วย 3 ดังนั้นเราควรตรวจสอบการดำเนินการลบในด้านซ้ายและขวา ด้านขวาสั้นเกินไป ความยาวด้านซ้ายเกือบ n = ความยาว (N)
  3. การทดสอบเบื้องต้นเช่น BPSW และ Miller-Rabin ใช้ปริมาณคงที่ของการยกกำลังแบบแยกส่วน ความซับซ้อนของมันคือ O (M (n) * n) ตามหน้านี้โดยที่ M (n) มีความซับซ้อนในการคูณ Java ใช้อัลกอริทึม Toom-Cook และ Karatsuba แต่เราจะใช้อัลกอริทึมอัจฉริยะเพื่อความเรียบง่าย M (n) n = 2 ดังนั้นความซับซ้อนในการทดสอบแบบดั้งเดิมคือ O (n 3 )
  4. เราควรตรวจสอบตัวเลขทั้งหมดจาก length = 6 ถึง 6629 ลองใช้ min = 1 และ max = n สำหรับ commonality ความซับซ้อนในการตรวจสอบทั้งหมดคือ O (1 3 + 2 3 + ... + n 3 ) = O ((n * (n + 1) / 2) 2 ) = O (n 4 )
  5. คำตอบของ Emilมีการตรวจสอบ asymptotics เดียวกัน แต่ปัจจัยคงที่ต่ำกว่า ตัวเลข "7" ยืนอยู่ตรงกลางของตัวเลข ด้านซ้ายและด้านขวาเกือบเท่ากัน มันทำให้ (n / 2) 4 * 2 n = 4 /8 Speedup: 8X ตัวเลขในรูปแบบ 9 ... 9Y9 ... 9 สามารถยาวกว่า 1.7 เท่าในแบบฟอร์ม X0 ... 0R มีเวลาตรวจสอบเท่ากัน

1
ขอบคุณสำหรับเครดิต แต่อัลกอริทึมของคุณซับซ้อนกว่าของฉันอย่างมาก! เยี่ยมมากและยินดีต้อนรับสู่ PPCG! :)
FryAmTheEggman

@FryAmTheEggman: ขอบคุณสำหรับความคิด! มันเป็นแรงบันดาลใจ
Qualtagh

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

13

Python 2 - 126 1221 1337 1719 2268 หลัก

999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999

'9' * 1944 + '7' + '9' * 323

มีจำนวนประมาณผลลัพธ์เกี่ยวกับ len (n) ^ 2 ของ Remove (n, startIndex, count) ฉันพยายามลดจำนวนเหล่านั้น หากมีตัวเลขจำนวนมากติดกันจะเหมือนกันตัวเลขที่เป็นผลลัพธ์เหล่านี้จำนวนมากสามารถถูกละเว้นได้เนื่องจากมันปรากฏขึ้นหลายครั้ง

ดังนั้นฉันจึงเอาไปสุดขั้วเพียง 9s และนายกเล็กน้อยในช่วงกลาง ฉันได้ดูนายกที่เปราะบางน้อยกว่า 1 ล้านคนแล้วเห็นว่ามีนายกที่บอบบางเช่นนั้น การค้นหาตัวเลขด้วย 2 9s ตอนท้ายใช้ได้ดีจริง ๆ ไม่แน่ใจว่าทำไม 1 หมายเลข, 3, หรือ 4 9s ในตอนท้ายผลลัพธ์ในช่วงเวลาที่บอบบางน้อย

มันใช้pyprimes โมดูล ฉันไม่แน่ใจว่ามันดีหรือไม่ มันใช้การทดสอบ miller_rabin ดังนั้นจึงน่าจะเป็น

โปรแกรมค้นหานายกที่เปราะบาง 126 หลักในเวลาประมาณ 1 นาทีและในช่วงเวลาที่เหลือก็ค้นหาได้โดยไม่ประสบความสำเร็จ

biggest_found = 80651

n = lambda a,b,c: '9'*a + b + '9'*c

for j in range(1000):
   for digit in '124578':
      for i in range(2000):
         number = int(n(i,digit,j))
         if is_prime(number):
            if (number > biggest_found):
               if all(not is_prime(int(n(i,digit,k))) for k in range(j)):
                  biggest_found = number
                  print(i+j+1, biggest_found)
            break

แก้ไข:

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

แก้ไข 2:

ทำให้โปรแกรมต้นฉบับของฉันเร็วขึ้น แต่ก็ยังไม่มีวิธีแก้ปัญหาที่มีมากกว่า 126 หลัก ดังนั้นฉันจึงกระโดดขึ้นรถไฟและค้นหา x 9s + 1 หลัก + y 9s ข้อได้เปรียบคือคุณต้องตรวจสอบหมายเลข O (n) สำหรับอันดับแรกหากคุณแก้ไข y พบว่า 1221 ค่อนข้างเร็ว

แก้ไข 3:

สำหรับหมายเลข 2268 หลักฉันใช้โปรแกรมเดียวกันเพียงแบ่งงานในหลายคอร์


3
"ในประมาณ 1 นาที" - ขออภัยต้องรายงานข้อผิดพลาด "พหูพจน์" : P
hichris123

ลักษณะความน่าจะเป็นของมิลเลอร์ - ราบินคือสิ่งที่ทำให้ฉันรู้สึกรำคาญกับผลงานชิ้นสุดท้ายของฉัน คุณอาจต้องการตรวจสอบด้วยอัลกอริทึมอื่นเช่นกัน
John Meacham

ทำไมคุณถึงตรวจสอบว่าตัวเลขที่เกิดขึ้นจากการลบตัวเลขจากจุดสิ้นสุดนั้นประกอบกันอย่างไร ทำไมไม่ตรวจสอบตัวเลขที่เกิดขึ้นจากการลบตัวเลขออกจากด้านหน้า?
isaacg

1
เพราะฉันตรวจสอบสิ่งเหล่านี้ก่อนหน้านี้ใน 'for i'-loop ที่นี่ฉันผนวก 9s ไว้ที่จุดเริ่มต้นและทำการตรวจสอบเฉพาะ เมื่อฉันพบจำนวนเฉพาะจำนวนแรกของแบบฟอร์มนี้ฉันรู้ว่าตัวเลขทั้งหมดที่น้อยกว่า 9s ในตอนเริ่มต้นนั้นไม่ได้เป็นจำนวนเฉพาะ และหลังจากตรวจสอบการลบ 9s ในตอนท้ายฉันหยุด (หยุดพัก) เพราะตอนนี้ทุกหมายเลขมีหมายเลขเฉพาะอยู่ภายในและดังนั้นจึงไม่ใช่เฉพาะ
Jakube

อาฉลาดมาก
isaacg

7

Python 2.7 - 429623069 99993799

ไม่มีการเพิ่มประสิทธิภาพ แต่อย่างใด เพียงใช้การสังเกตเล็กน้อยเกี่ยวกับช่วงเวลาที่บอบบาง (ขอบคุณ Rainbolt ในการแชท):

  1. ช่วงเวลาที่เปราะบางต้องสิ้นสุดใน 1 หรือ 9 (ช่วงเวลาไม่เท่ากันและเลขตัวสุดท้ายจะต้องไม่เป็นจำนวนเฉพาะ)
  2. ช่วงเวลาที่เปราะบางที่ลงท้ายด้วย 1 จะต้องเริ่มต้นด้วย 8 หรือ 9 (หมายเลขแรกต้องไม่เป็นจำนวนเฉพาะและ 11, 41 และ 61 และเป็นช่วงเวลาทั้งหมด)
  3. ช่วงเวลาที่เปราะบางที่ลงท้ายด้วย 9 ต้องเริ่มต้นด้วย 4,6 หรือ 9 (ดูเหตุผลสำหรับ 1 แต่ 89 เท่านั้นเป็นไพรม์)

แค่พยายามทำให้ลูกบอลกลิ้ง :)

เทคนิคนี้ใช้งานได้นานกว่า 15 นาที แต่จะตรวจสอบตัวเลขเพียงครั้งเดียวในช่วงต่อเวลาพิเศษ

is_primeถูกนำมาจากที่นี่ (isaacg ใช้ที่นี่ ) และน่าจะเป็น

def substrings(a):
    l=len(a)
    out=set()
    for i in range(l):
        for j in range(l-i):
            out.add(a[:i]+a[len(a)-j:])
    return out

import time

n=9
while time.clock()<15*60:
    if is_prime(n):
        if not any(map(lambda n: n!='' and is_prime(int(n)), substrings(`n`))):
            print n
    t=`n`
    if n%10==9 and t[0]=='8':n+=2
    elif n%10==1 and t[0]!='8':n+=8
    elif t[0]=='1' or is_prime(int(t[0])):n+=10**~-len(t)
    else:n+=10

เพียงแค่ทราบเมื่อฉันเริ่มต้นนี้กับฉันได้รับถึงn=429623069 482704669ตัวเลขพิเศษดูเหมือนจะฆ่ากลยุทธ์นี้จริง ๆ ...


ไม่เลวสำหรับการเริ่มต้น! แม้ว่าดูเหมือนว่า is_prime จะทำการตรวจสอบ deteterministic แบบเต็มสำหรับค่า 32 บิตซึ่งมากเกินไปเล็กน้อย ฉันคิดว่าวิธี is_prime อาจทำงานได้เร็วขึ้นหากคุณจะแสดงความคิดเห็นในส่วนการทดลองเต็มรูปแบบ
Suboptimus Prime

@SuboptimusPrime โอ้ขอบคุณ ฉันไม่ได้ดู: P
FryAmTheEggman

@SuboptimusPrime ฉันคิดว่าการตรวจสอบที่กำหนดขึ้นแบบเต็มจะเร็วกว่าสำหรับค่าเล็กน้อยเพราะผู้เขียนได้กำหนดขั้นตอนที่ต้องดำเนินการระหว่างปัจจัยผู้สมัคร ขอขอบคุณอีกครั้งสำหรับความคิด แต่ดูเหมือนว่าได้เร็วขึ้นมากเมื่อออกว่าใน :)
FryAmTheEggman

การแก้ไขเล็กน้อยสำหรับคำตอบของคุณ: 91 = 13x7 ดังนั้น 91 จึงเป็นคอมโพสิตและช่วงเวลาที่เปราะบางที่ลงท้ายด้วย 1 สามารถเริ่มต้นด้วย 9 ได้
Suboptimus Prime

@SuboptimusPrime ค่อนข้างถูกต้องไม่ทราบว่าฉันทำสิ่งนั้นผิด ค่าที่ฉันโพสต์ควรจะยังคงใช้ได้เพราะฉันเพิ่งข้ามค่าที่เป็นไปได้บางอย่าง
FryAmTheEggman

7

Python 2, 828 หลัก 5048 หลัก

99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
155*'9'+'7'+4892*'9'

@Jakube ชี้ให้เห็นนายกรัฐมนตรีคนแรกที่ฉันส่งมานั้นไม่บอบบางเพราะข้อผิดพลาดในรหัสของฉัน การแก้ไขข้อผิดพลาดนั้นง่าย แต่ก็ทำให้อัลกอริทึมช้าลงอย่างมาก

ฉัน จำกัด ตัวเองเป็นชุดย่อยที่สามารถค้นหาได้ง่ายของช่วงเวลาที่บอบบางซึ่งประกอบด้วยเพียงตัวเลข 9 และ 7 หลักเท่านั้น

def fragile_prime_generator(x, b_max):
  bs, cs = set(), set()
  prime = dict()

  def test_prime(b,c):
    if (b,c) not in prime:
      prime[(b,c)] = is_prime(int('9'*b+`x`+'9'*c))
    return prime[(b,c)]

  def test_frag(b,c):
    for b2 in xrange(b):
      if test_prime(b2,c):
        bs.add(b2)
        return False
    for c2 in xrange(c):
      if test_prime(b,c2):
        cs.add(c2)
        return False
    return True

  a = 1
  while len(bs)<b_max:
    for b in xrange(min(a, b_max)):
      c = a-b
      if b not in bs and c not in cs and test_prime(b,c):
        bs.add(b)
        cs.add(c)
        if test_frag(b,c): yield b,c
    a += 1
  print "no more fragile primes of this form"

for b,c in fragile_prime_generator(7, 222):
  print ("%d digit fragile prime found: %d*'9'+'%d'+%d*'9'"
          % (b+c+1, b, x, c))

ฉันใช้is_primeฟังก์ชั่นเดียวกัน(จากตรงนี้ ) เป็น @FryAmTheEggman

แก้ไข:

ฉันทำการเปลี่ยนแปลงสองครั้งเพื่อทำให้อัลกอริทึมเร็วขึ้น:

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

  • สำหรับตัวเลขของรูปแบบที่b*'9' + '7' + c*'9'ฉัน จำกัด bขนาดของ ขีด จำกัด ที่ต่ำกว่าต้องตรวจสอบตัวเลขที่น้อยลง แต่โอกาสที่จะเพิ่มขึ้นจะไม่พบนายกที่บอบบางมาก ๆ เลย ฉันเลือก 222 ตามอำเภอใจ

เช็คหลักสองสามหลักเพียงครั้งเดียวสามารถใช้โปรแกรมของฉันได้สองสามวินาที ดังนั้นฉันอาจไม่สามารถทำได้ดีกว่านี้ด้วยวิธีนี้

โปรดตรวจสอบความถูกต้องของการส่งของฉัน เนื่องจากความน่าจะเป็นอันดับแรกตรวจสอบจำนวนของฉันในทางทฤษฎีอาจไม่สำคัญ แต่ถ้าเป็นก็ควรจะเปราะบาง หรือฉันทำอะไรผิดไป :-)


2
นายกที่คุณพบนั้นไม่บอบบาง หากคุณโทรลบ (n, 83,838) [ลบทุกอย่างยกเว้นตัวเลข 82 ตัวแรก] คุณจะพบว่ามีจำนวนเฉพาะ
Jakube

1
อ่าขอบคุณ @Jakube ฉันพยายามที่จะฉลาดเกินไป ปรากฎว่าฉันข้ามการตรวจสอบแบบดั้งเดิมมากขึ้นแล้วฉันควรจะมี ฉันกำลังจะไปแก้ไข
Emil

1
ตรวจสอบอีกครั้งตอนนี้ผลลัพธ์ของคุณถูกต้องแล้ว
Jakube

หมายเลข 5048 หลักของคุณคือจำนวนเฉพาะที่บอบบางตามโปรแกรมของฉัน
Suboptimus Prime

@SuboptimusPrime: เยี่ยมมากขอบคุณสำหรับการตรวจสอบ!
Emil

4

C #, 10039 28164 หลัก

6 0{28157} 169669

แก้ไข:ฉันได้ทำโปรแกรมอื่นตามอัลกอริทึมของ Qualtagh พร้อมการแก้ไขเล็กน้อย:

  • ฉันกำลังค้นหาตัวเลขของรูปแบบ L000 ... 000R โดยที่ L เหลือคอมโพสิต R คือคอมโพสิตที่ถูกต้อง ฉันอนุญาตให้หมายเลขคอมโพสิตด้านซ้าย L มีตัวเลขหลายหลักแม้ว่าส่วนใหญ่จะเป็นการเปลี่ยนแปลงโวหารและอาจไม่มีผลต่อประสิทธิภาพของอัลกอริทึม
  • ฉันได้เพิ่มมัลติเธรดเพื่อเพิ่มความเร็วในการค้นหา
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Mpir.NET;

class Program
{
    const int PrimeNotFound = int.MaxValue;

    private static BitArray _primeSieve;
    private static HashSet<Tuple<int, int>> _templatesToSkip = new HashSet<Tuple<int, int>>();

    static void Main(string[] args)
    {
        int bestDigitCount = 0;
        foreach (Tuple<int, int> template in GetTemplates())
        {
            int left = template.Item1;
            int right = template.Item2;
            if (SkipTemplate(left, right))
                continue;

            int zeroCount = GetZeroCountOfPrime(left, right);
            if (zeroCount != PrimeNotFound)
            {
                int digitCount = left.ToString().Length + right.ToString().Length + zeroCount;
                if (digitCount >= bestDigitCount)
                {
                    string primeStr = left + " 0{" + zeroCount + "} " + right;
                    Console.WriteLine("testing " + primeStr);
                    bool isFragile = IsFragile(left, right, zeroCount);
                    Console.WriteLine(primeStr + " is fragile: " + isFragile);

                    if (isFragile)
                        bestDigitCount = digitCount;
                }

                _templatesToSkip.Add(template);
            }
        }
    }

    private static int GetZeroCountOfPrime(int left, int right)
    {
        _zeroCount = 0;

        int threadCount = Environment.ProcessorCount;
        Task<int>[] tasks = new Task<int>[threadCount];
        for (int i = 0; i < threadCount; i++)
            tasks[i] = Task.Run(() => InternalGetZeroCountOfPrime(left, right));
        Task.WaitAll(tasks);

        return tasks.Min(task => task.Result);
    }

    private static int _zeroCount;

    private static int InternalGetZeroCountOfPrime(int left, int right)
    {
        const int maxZeroCount = 40000;
        int zeroCount = Interlocked.Increment(ref _zeroCount);
        while (zeroCount <= maxZeroCount)
        {
            if (zeroCount % 1000 == 0)
                Console.WriteLine("testing " + left + " 0{" + zeroCount + "} " + right);

            if (IsPrime(left, right, zeroCount))
            {
                Interlocked.Add(ref _zeroCount, maxZeroCount);
                return zeroCount;
            }
            else
                zeroCount = Interlocked.Increment(ref _zeroCount);
        }

        return PrimeNotFound;
    }

    private static bool SkipTemplate(int left, int right)
    {
        for (int leftDiv = 1; leftDiv <= left; leftDiv *= 10)
            for (int rightDiv = 1; rightDiv <= right; rightDiv *= 10)
                if (_templatesToSkip.Contains(Tuple.Create(left / leftDiv, right % (rightDiv * 10))))
                    return true;

        return false;
    }

    private static bool IsPrime(int left, int right, int zeroCount)
    {
        return IsPrime(left.ToString() + new string('0', zeroCount) + right.ToString());
    }

    private static bool IsPrime(string left, string right, int zeroCount)
    {
        return IsPrime(left + new string('0', zeroCount) + right);
    }

    private static bool IsPrime(string s)
    {
        using (mpz_t n = new mpz_t(s))
        {
            return n.IsProbablyPrimeRabinMiller(20);
        }
    }

    private static bool IsFragile(int left, int right, int zeroCount)
    {
        string leftStr = left.ToString();
        string rightStr = right.ToString();

        for (int startIndex = 0; startIndex < leftStr.Length - 1; startIndex++)
            for (int count = 1; count < leftStr.Length - startIndex; count++)
                if (IsPrime(leftStr.Remove(startIndex, count), rightStr, zeroCount))
                    return false;

        for (int startIndex = 1; startIndex < rightStr.Length; startIndex++)
            for (int count = 1; count <= rightStr.Length - startIndex; count++)
                if (IsPrime(leftStr, rightStr.Remove(startIndex, count), zeroCount))
                    return false;

        return true;
    }

    private static IEnumerable<Tuple<int, int>> GetTemplates()
    {
        const int maxDigitCount = 8;
        PreparePrimeSieve((int)BigInteger.Pow(10, maxDigitCount));
        for (int digitCount = 2; digitCount <= maxDigitCount; digitCount++)
        {
            for (int leftCount = 1; leftCount < digitCount; leftCount++)
            {
                int rightCount = digitCount - leftCount;
                int maxLeft = (int)BigInteger.Pow(10, leftCount);
                int maxRight = (int)BigInteger.Pow(10, rightCount);

                for (int left = maxLeft / 10; left < maxLeft; left++)
                    for (int right = maxRight / 10; right < maxRight; right++)
                        if (IsValidTemplate(left, right, leftCount, rightCount))
                            yield return Tuple.Create(left, right);
            }

        }
    }

    private static void PreparePrimeSieve(int limit)
    {
        _primeSieve = new BitArray(limit + 1, true);
        _primeSieve[0] = false;
        _primeSieve[1] = false;

        for (int i = 2; i * i <= limit; i++)
            if (_primeSieve[i])
                for (int j = i * i; j <= limit; j += i)
                    _primeSieve[j] = false;
    }

    private static bool IsValidTemplate(int left, int right, int leftCount, int rightCount)
    {
        int rightDigit = right % 10;
        if ((rightDigit != 1) && (rightDigit != 9))
            return false;

        if (left % 10 == 0)
            return false;

        if ((left + right) % 3 == 0)
            return false;

        if (!Coprime(left, right))
            return false;

        int leftDiv = 1;
        for (int i = 0; i <= leftCount; i++)
        {
            int rightDiv = 1;
            for (int j = 0; j <= rightCount; j++)
            {
                int combination = left / leftDiv * rightDiv + right % rightDiv;
                if (_primeSieve[combination])
                    return false;

                rightDiv *= 10;
            }

            leftDiv *= 10;
        }

        return true;
    }

    private static bool Coprime(int a, int b)
    {
        while (b != 0)
        {
            int t = b;
            b = a % b;
            a = t;
        }
        return a == 1;
    }
}

คำตอบเก่า:

8 0{5436} 4 0{4600} 1

รูปแบบที่โดดเด่นบางประการสำหรับช่วงเวลาที่บอบบาง:

600..00X00..009
900..00X00..009
800..00X00..001
999..99X99..999

โดยที่ X สามารถเป็น 1, 2, 4, 5, 7 หรือ 8

สำหรับตัวเลขดังกล่าวเราจะต้องพิจารณาRemoveการดำเนินการที่เป็นไปได้ (ความยาว - 1) เท่านั้น อื่น ๆRemoveดำเนินการสร้างจำนวนซ้ำหรือรวมกันอย่างชัดเจน ฉันพยายามค้นหาตัวเลขทั้งหมดที่มีมากถึง 800 หลักและสังเกตว่า 4 รูปแบบเกิดขึ้นบ่อยกว่าที่เหลือ: 8007001, 8004001, 9997999 และ 6004009 เนื่องจาก Emil และ Jakube ใช้รูปแบบ 999X999 ฉันจึงตัดสินใจใช้ 8004001 เพียง เพื่อเพิ่มความหลากหลาย

ฉันได้เพิ่มการเพิ่มประสิทธิภาพต่อไปนี้ให้กับอัลกอริทึม:

  • ฉันเริ่มค้นหาจากตัวเลขที่มี 7000 หลักแล้วเพิ่มความยาวเป็น 1500 ทุกครั้งที่พบไพรม์ที่เปราะบาง หากไม่มีความเปราะบางที่มีความยาวที่กำหนดฉันจะเพิ่มมันทีละ 1, 7000 และ 1500 เป็นเพียงตัวเลขที่เหมาะสม
  • ฉันใช้มัลติเธรดเพื่อค้นหาตัวเลขที่มีความยาวต่างกันในเวลาเดียวกัน
  • ผลลัพธ์ของการตรวจสอบเฉพาะแต่ละครั้งจะถูกเก็บไว้ในตารางแฮชเพื่อป้องกันการตรวจสอบซ้ำ
  • ฉันใช้การติดตั้ง Miller-Rabin จากMpir.NETซึ่งเร็วมาก (MPIR เป็นทางแยกของ GMP)
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Mpir.NET;

class Program
{
    const string _template = "8041";

    private static ConcurrentDictionary<Tuple<int, int>, byte> _compositeNumbers = new ConcurrentDictionary<Tuple<int, int>, byte>();
    private static ConcurrentDictionary<int, int> _leftPrimes = new ConcurrentDictionary<int, int>();
    private static ConcurrentDictionary<int, int> _rightPrimes = new ConcurrentDictionary<int, int>();

    static void Main(string[] args)
    {
        int threadCount = Environment.ProcessorCount;
        Task[] tasks = new Task[threadCount];
        for (int i = 0; i < threadCount; i++)
        {
            int index = i;
            tasks[index] = Task.Run(() => SearchFragilePrimes());
        }
        Task.WaitAll(tasks);
    }

    private const int _lengthIncrement = 1500;
    private static int _length = 7000;
    private static object _lengthLock = new object();
    private static object _consoleLock = new object();

    private static void SearchFragilePrimes()
    {
        int length;
        lock (_lengthLock)
        {
            _length++;
            length = _length;
        }

        while (true)
        {
            lock (_consoleLock)
            {
                Console.WriteLine("{0:T}: length = {1}", DateTime.Now, length);
            }

            bool found = false;
            for (int rightCount = 1; rightCount <= length - 2; rightCount++)
            {
                int leftCount = length - rightCount - 1;
                if (IsFragilePrime(leftCount, rightCount))
                {
                    lock (_consoleLock)
                    {
                        Console.WriteLine("{0:T}: {1} {2}{{{3}}} {4} {2}{{{5}}} {6}",
                            DateTime.Now, _template[0], _template[1], leftCount - 1,
                            _template[2], rightCount - 1, _template[3]);
                    }
                    found = true;
                    break;
                }
            }

            lock (_lengthLock)
            {
                if (found && (_length < length + _lengthIncrement / 2))
                    _length += _lengthIncrement;
                else
                    _length++;
                length = _length;
            }
        }
    }

    private static bool IsFragilePrime(int leftCount, int rightCount)
    {
        int count;
        if (_leftPrimes.TryGetValue(leftCount, out count))
            if (count < rightCount)
                return false;

        if (_rightPrimes.TryGetValue(rightCount, out count))
            if (count < leftCount)
                return false;

        if (!IsPrime(leftCount, rightCount))
            return false;

        for (int i = 0; i < leftCount; i++)
            if (IsPrime(i, rightCount))
                return false;

        for (int i = 0; i < rightCount; i++)
            if (IsPrime(leftCount, i))
                return false;

        return true;
    }

    private static bool IsPrime(int leftCount, int rightCount)
    {
        Tuple<int, int> tuple = Tuple.Create(leftCount, rightCount);
        if (_compositeNumbers.ContainsKey(tuple))
            return false;

        using (mpz_t n = new mpz_t(BuildStr(leftCount, rightCount)))
        {
            bool result = n.IsProbablyPrimeRabinMiller(20);

            if (result)
            {
                _leftPrimes.TryAdd(leftCount, rightCount);
                _rightPrimes.TryAdd(rightCount, leftCount);
            }
            else
                _compositeNumbers.TryAdd(tuple, 0);

            return result;
        }
    }

    private static string BuildStr(int leftCount, int rightCount)
    {
        char[] chars = new char[leftCount + rightCount + 1];
        for (int i = 0; i < chars.Length; i++)
            chars[i] = _template[1];
        chars[0] = _template[0];
        chars[leftCount + rightCount] = _template[3];
        chars[leftCount] = _template[2];
        return new string(chars);
    }
}

ขณะที่ฉันพยายามยืนยันคำตอบแรกของคุณคุณได้โพสต์ใหม่แล้ว)) ตรวจสอบแล้วใช้เวลา 24 ชั่วโมง ดูเหมือนว่าคำตอบจะถูกต้อง ฉันไม่อยากจะเชื่อเลยว่า BigInteger ของ Java นั้นช้ากว่าการใช้งานทั่วไปมาก ฉันคิดว่าช้ากว่า 2, 3 หรือ 10 เท่า แต่ 24 ชั่วโมงต่อหลายนาทีนั้นมากเกินไป
Qualtagh

@Qualtagh เพื่อความยุติธรรมหมายเลข 1,3939 หลักใช้เวลา 35 ชั่วโมงในการค้นหาเนื่องจากอัลกอริทึมที่ด้อยกว่า :) โปรแกรมปัจจุบันของฉันใช้เวลาประมาณ 3 นาทีในการค้นหาหมายเลข 6629 หลักของคุณและ 6 ชั่วโมงเพื่อค้นหา 28164 หนึ่งหลัก
Suboptimus Prime

คำตอบแรกของคุณถูกต้อง ยืนยันแล้ว! การยืนยันใช้เวลา 48 ชั่วโมง และฉันจะไม่ลองยืนยันคำตอบที่สอง)) ฉันสงสัยว่าทำไม BigInteger จึงช้าเมื่อเปรียบเทียบกับ MPIR มันเป็นเพียง JVM / ความแตกต่างพื้นเมือง? ฉันตั้งค่าสถานะ "- เซิร์ฟเวอร์" ดังนั้นคาดว่ารหัสจะรวบรวม JIT อัลกอริทึมของการยกกำลังแบบแยกส่วนแตกต่างกัน: ทั้ง Java และ MPIR ใช้ 2 <sup> k </sup> - หน้าต่างบานเลื่อนสไลด์ แต่ k = 3 ได้รับการแก้ไขใน Java และ MPIR เลือก k ตามขนาดของเลขชี้กำลัง MPIR ใช้การคำนวณแบบขนานบนหลายคอร์หรืออาจเป็น GPU BigInteger ของ Java ไม่ได้
Qualtagh

1
@ Qualitytagh ฉันค่อนข้างแน่ใจว่า MPIR ใช้ CPU แกนเดียวเท่านั้น ฉันได้เพิ่มมัลติเธรดตัวเองซึ่งทำให้การค้นหาเร็วขึ้นเกือบสี่เท่าบน CPU แบบ quad-core ฉันไม่ได้เปรียบเทียบการใช้งานภายในของ MPIR และ Java BigInteger แต่ฉันเดาว่า MPIR กำลังใช้อัลกอริธึมที่ดีกว่าสำหรับการคูณและการหารแบบแยกส่วน นอกจากนี้อาจเป็นการปรับปรุงที่ดีกว่าสำหรับซีพียู 64 บิต (ดูมาตรฐานในโพสต์บล็อกนี้ )
Suboptimus Prime

2
MPIR เป็นแกนเดียวแน่นอนและไม่ใช้ GPU มันเป็นการผสมผสานกันอย่างลงตัวของรหัส C และแอสเซมเบลอร์ มีรุ่น MPIR ที่ใช้เฉพาะ C (สำหรับเหตุผลด้านการพกพา) แต่รุ่น C + ASM นั้นเร็วกว่าอย่างเห็นได้ชัด รุ่น MPIR ที่ฉันใช้สำหรับ MPIR.Net คือชุดคำสั่ง C + ASM โดยใช้ชุดคำสั่ง K8 (1st gen x64) เพราะฉันต้องการให้ MPIR.Net ทำงานบนพีซี x64 ทั้งหมด เวอร์ชันสำหรับชุดคำสั่งในภายหลังนั้นไม่ได้เร็วขึ้นอย่างเห็นได้ชัดในเกณฑ์มาตรฐาน crypto ของฉัน แต่แน่นอนว่าอาจแตกต่างกันสำหรับการดำเนินการอื่น ๆ
John Reynolds

2

Haskell - 1220 1277 หลักได้ รับการแก้ไขสำหรับ reals จริงๆ

99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997999999999999999999999999999999999999999999999999999999999999999999999

9{1150} 7 9{69}

ดีกว่าหนึ่ง - 1277 หลัก

9{871} 8 9{405}

รหัส Haskell

downADigit :: Integer -> [Integer]
downADigit n = f [] 1 where
     f xs a | nma /= n = f (((n `div` a10)*a + nma):xs) a10
            | otherwise = xs where
        a10 = a * 10
        nma = n `mod` a

isFragile = all (not . isPrime') . downADigit
findNextPrime :: Integer -> Integer
findNextPrime n | even n = f (n + 1)
                | otherwise = f n where
    f n | isPrime' n  = n
        | otherwise = f (n + 2)

primesFrom n = f (findNextPrime n) where
    f n = n:f (findNextPrime $ n + 1)

primeLimit = 10000

isPrime' n | n < primeLimit = isPrime n
isPrime' n = all (millerRabinPrimality n) [2,3,5,7,11,13,17,19,984,7283,6628,8398,2983,9849,2739]

-- (eq. to) find2km (2^k * n) = (k,n)
find2km :: Integer -> (Integer,Integer)
find2km n = f 0 n
    where 
        f k m
            | r == 1 = (k,m)
            | otherwise = f (k+1) q
            where (q,r) = quotRem m 2        

-- n is the number to test; a is the (presumably randomly chosen) witness
millerRabinPrimality :: Integer -> Integer -> Bool
millerRabinPrimality n a
    | a <= 1 || a >= n-1 = 
        error $ "millerRabinPrimality: a out of range (" 
              ++ show a ++ " for "++ show n ++ ")" 
    | n < 2 = False
    | even n = False
    | b0 == 1 || b0 == n' = True
    | otherwise = iter (tail b)
    where
        n' = n-1
        (k,m) = find2km n'
        b0 = powMod n a m
        b = take (fromIntegral k) $ iterate (squareMod n) b0
        iter [] = False
        iter (x:xs)
            | x == 1 = False
            | x == n' = True
            | otherwise = iter xs

-- (eq. to) pow' (*) (^2) n k = n^k
pow' :: (Num a, Integral b) => (a->a->a) -> (a->a) -> a -> b -> a
pow' _ _ _ 0 = 1
pow' mul sq x' n' = f x' n' 1
    where 
        f x n y
            | n == 1 = x `mul` y
            | r == 0 = f x2 q y
            | otherwise = f x2 q (x `mul` y)
            where
                (q,r) = quotRem n 2
                x2 = sq x

mulMod :: Integral a => a -> a -> a -> a
mulMod a b c = (b * c) `mod` a
squareMod :: Integral a => a -> a -> a
squareMod a b = (b * b) `rem` a

-- (eq. to) powMod m n k = n^k `mod` m
powMod :: Integral a => a -> a -> a -> a
powMod m = pow' (mulMod m) (squareMod m)

-- simple for small primes
primes :: [Integer]
primes = 2:3:primes' where
    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
isPrime :: Integer -> Bool
isPrime n | n < 2 = False
          | otherwise = f primes where
            f (p:ps) | p*p <= n = if n `rem` p == 0 then False else f ps
                     | otherwise = True

main = do
    print . head $ filter isFragile (primesFrom $ 10^1000)

ฉันคิดว่าคุณสามารถลบทุกอย่างยกเว้น 3 ล่าสุด ...
Sp3000

มันจะสิ้นสุดลงใน 5 ถ้าฉันลบ 3 ตัวสุดท้ายดังนั้นหารด้วย 5
John Meacham

2
ไม่ฉันหมายถึงลบทุกอย่างออกจนกว่าคุณจะเหลือ 3 ครั้งสุดท้ายซึ่งเป็นสิ่งสำคัญ
Sp3000

1
@JohnMeacham โปรแกรมของฉันแนะนำว่าหมายเลขนี้จะเปลี่ยนเป็นไพรม์ถ้าคุณลบ 386 หลักจากด้านซ้าย
Suboptimus Prime

1
โปรดยืนยันหมายเลขของคุณก่อนโพสต์ หากคุณลบตัวเลข 1256 หลักทางซ้ายจากหมายเลข 1276 หลักของคุณคุณจะได้รับ 99999994999999999999 ซึ่งเป็นตัวเลขที่ดีที่สุด
Suboptimus Prime
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.