가장 깨지기 쉬운 프라임 찾기 숫자에서 숫자

위치 의 숫자 부터 시작하여 숫자에서 숫자 Remove(n, startIndex, count)를 제거 하는 기능 을 고려하십시오 . 예 :countnstartIndex

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

우리는 가능한 모든 Remove연산이 프라임이 아닌 경우 소수 X를 깨지기 쉬운 것으로 부릅니다 . 예를 들어, 80651은 다음과 같은 숫자가 모두 소수가 아니기 때문에 취약한 소수입니다.

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

가장 깨지기 쉬운 소수를 찾는 프로그램을 작성하십시오. 편집 : 시간 제한을 우회하는 비교적 공정한 방법이 있었으므로 시간 제한을 제거했습니다.

점수는 프로그램에서 찾은 깨지기 쉬운 소수입니다. 동점 일 경우, 이전 제출물이 이깁니다.

규칙

  • 모든 언어 및 타사 라이브러리를 사용할 수 있습니다.
  • 자신의 하드웨어에서 프로그램을 실행합니다.
  • 확률 우선 성 테스트를 사용할 수 있습니다.
  • 모든 것은 기본 10에 있습니다.

주요 항목

  • Qualtagh의 6629 자리 (자바)
  • Emil이 작성한 5048 자리 (Python 2)
  • Jakube의 2268 자리 숫자 (Python 2)

편집 : 나는 내 자신의 답변을 추가했습니다.

  • Qualtagh의 알고리즘 (C #)을 기반으로 Suboptimus Prime의 28164 자리 숫자


답변

자바- 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입니다.

더 깊이 파면 어떨까요?

트리 구조가됩니다.

                        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 등 모든 첫 번째 복합 번호를 반복 할 것입니다.

0으로 시작하는 숫자는 우선 순위를 검사하지 않지만 추가 숫자를 빌드하는 데 필요합니다.

X00 … 00R 형식의 대상 번호 N을 찾습니다. 여기서 X는 4, 6, 8 또는 9 중 하나이고 R은 올바른 합성입니다. X는 소수 일 수 없습니다. X는 0이 될 수 없습니다. R이 1 또는 9로 끝나면 N은 11 또는 19를 포함하므로 X는 1이 될 수 없습니다.

“제거”작업 후 XR에 소수가 포함되어 있으면 XYR에도 Y에 대한 소수가 포함됩니다. 따라서 R에서 시작하는 분기를 통과해서는 안됩니다.

X를 상수라고합시다 (6).

의사 코드 :

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 + zeros + R 형식으로 소수를 찾는 데 너무 오래 걸릴 수 있기 때문에 zeros 수량을 제한해야합니다.

실제 코드는 매우 장황하며 여기 에서 찾을 수 있습니다 .

긴 int 범위의 숫자에 대한 우선 순위 테스트는 Miller 테스트의 결정적 변형에 의해 수행됩니다. BigInteger 번호의 경우 시험 분할이 먼저 수행 된 다음 BailliePSW 테스트가 수행됩니다. 확률 적이지만 확실합니다. 그리고 Miller-Rabin 테스트보다 빠릅니다 (밀러 라빈에서 그러한 큰 숫자를 충분히 반복하려면 많은 반복을 수행해야합니다).

편집 : 첫 번째 시도가 잘못되었습니다. X0 … 0R이 소수이면 R로 시작하는 분기도 무시해야합니다. 그러면 X0 … 0YR은 연약한 소수가 아닙니다. 그래서 추가 점검이 추가되었습니다. 이 솔루션은 올바른 것 같습니다.

편집 2 : 최적화가 추가되었습니다. (X + R)을 3으로 나눌 수 있으면 (X + zeros + R)도 3으로 나눌 수 있습니다. 따라서이 경우 (X + zeros + R)은 소수가 아니며 그러한 R은 건너 뛸 수 있습니다.

편집 3 : 소수 또는 마지막 위치가 아닌 경우 소수를 건너 뛸 필요가 없습니다. 따라서 21 또는 51과 같은 결말은 괜찮습니다. 그러나 별다른 변화는 없습니다.

결론 :

  1. 마지막 대답은 100 분 동안 깨지기 쉬운 지 확인하는 것이 었습니다. 답변을 검색하는 데 (앞의 모든 변형 확인) 약 15 분이 걸렸습니다. 예, 검색 시간을 제한하는 것은 의미가 없습니다 (대상 번호에서 검색을 시작할 수 있으므로 시간은 0이됩니다). 그러나이 질문 에서처럼 검사 시간을 제한하는 것이 의미가있을 수 있습니다 .
  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. 우리는 길이 = 6에서 6629 사이의 모든 숫자를 확인해야합니다. 공통성을 위해 min = 1과 max = n을 취합시다. 전체 검사 복잡도는 O (1 3 + 2 3 + … + n 3 ) = O ((n * (n + 1) / 2) 2 ) = O (n 4 )입니다.
  5. 에밀의 대답 은 무증상 검사와 동일합니다. 그러나 상수는 낮습니다. 숫자 “7”은 숫자 중간에 서 있습니다. 왼쪽과 오른쪽은 거의 같습니다. 또한 (N / 2) 범 4 * 2 = N 4 배속 / 8 시간 단축. 9 … 9Y9 … 9 형식의 숫자는 동일한 점검 시간을 갖는 X0 … 0R 형식보다 1.7 배 더 길 수 있습니다.

답변

파이썬 2 – (126) 1221 1337 1719 2268 자리

999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999

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

Remove (n, startIndex, count)의 결과는 약 len (n) ^ 2 개입니다. 나는 그 숫자를 최소화하려고 노력했다. 서로 옆에 많은 자릿수가 동일하면 여러 번 나타나기 때문에 이러한 많은 숫자가 무시 될 수 있습니다.

그래서 나는 9 초에 약간의 소수를 가져갔습니다. 나는 또한 1 백만 이하의 연약한 소수를 보았고, 그러한 연약한 소수가 있음을 보았다. 마지막에 2 9가있는 숫자를 검색하면 실제로 잘 작동하지만 이유는 확실하지 않습니다. 마지막에 1, 3 또는 4 9를 사용하면 연약한 소수가 작아집니다.

pyprimes 모듈을 사용합니다 . 그것이 좋은지 확실하지 않습니다. miller_rabin 테스트를 사용하므로 확률 적입니다.

이 프로그램은 약 1 분 안에이 126 자리의 깨지기 쉬운 프라임을 찾고 나머지 시간 동안 성공하지 않고 검색합니다.

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 digit + y 9s를 검색했습니다. 장점은 y를 고치면 O (n) 수에 대한 우선 순위를 확인해야한다는 것입니다. 1221은 다소 빨리 발견됩니다.

편집 3 :

2268 자리 숫자의 경우 동일한 프로그램을 사용하고 여러 코어의 작업 만 나눕니다.


답변

파이썬 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. 여분의 숫자는 실제로이 전략을 죽이는 것 같습니다 …


답변

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를 임의로 선택했습니다.

수천 자리에서 단일 소수 검사는 이미 내 프로그램을 몇 초가 걸릴 수 있습니다. 따라서이 접근법으로 더 잘 할 수는 없습니다.

제출 한 내용의 정확성을 확인하십시오. 확률 적 우선 순위 점검으로 인해 내 숫자는 이론적으로 소수가 될 수 없지만 그 숫자는 깨지기 쉬워야합니다. 또는 내가 잘못한 것입니다. 🙂


답변

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 일 수 있습니다.

이러한 숫자의 경우 가능한 길이 만 (길이-1) 만 고려하면 Remove됩니다. 다른 Remove연산은 중복 또는 명백하게 복합 숫자를 생성합니다. 800 자리까지의 모든 숫자를 검색하려고 시도했지만 나머지 패턴보다 8007001, 8004001, 9997999 및 6004009의 4 가지 패턴이 더 자주 나타납니다. Emil과 Jakube가 999X999 패턴을 사용하고 있기 때문에 8004001을 사용하기로 결정했습니다. 다양성을 추가하십시오.

알고리즘에 다음 최적화를 추가했습니다.

  • 7000 자리 숫자로 검색을 시작한 다음 깨지기 쉬운 소수가 발견 될 때마다 길이를 1500 씩 증가시킵니다. 주어진 길이의 깨지기 쉬운 소수가 없으면 1 씩 증가시킵니다. 7000과 1500은 적절하게 보이는 임의의 숫자입니다.
  • 멀티 스레딩을 사용하여 길이가 다른 숫자를 동시에 검색하고 있습니다.
  • 각 프라임 검사의 결과는 중복 검사를 방지하기 위해 해시 테이블에 저장됩니다.
  • Mpir.NET 에서 Miller-Rabin 구현을 사용하고 있습니다 .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);
    }
}

답변

Haskell- 1220 자리 숫자 는 실제 실수 수정되었습니다.

99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997999999999999999999999999999999999999999999999999999999999999999999999

9{1150} 7 9{69}

더 나은 하나-1277 자리

9{871} 8 9{405}

하스켈 코드

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)