가장 깨지기 쉬운 프라임 찾기


21

위치 의 숫자 부터 시작하여 숫자에서 숫자 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 자리 숫자

5
답변을 하드 코딩하지 않아도 큰 깨지기 쉬운 소수에 매우 가까운 지점에서 검색을 시작할 수 있습니다. 분명히, 아무도 1에서 검색을 시작하기를 원하지 않습니다. 기본적으로 답변을 하드 코딩하기 전에 어떻게 검색을 시작할 수 있습니까? 그건 그렇고 나는 도전을 좋아합니다.
Rainbolt

2
@SuboptimusPrime 대신에 시간 제한을 완전히 제거 할 수 있습니다. 어쨌든 다음 시점을 찾는 것이 위업이 될 정도로 드물다고 생각하기 때문입니다. ( codegolf.stackexchange.com/questions/41021/…과 유사 )
Martin Ender


7
컴퓨터 속도가 느린 사용자에게는 여전히 불리한 점이 있습니다
John Dvorak

11
"가장 큰 깨지기 쉬운 소수를 찾는 프로그램을 쓰십시오"는 "가장 큰 깨지기 쉬운 소수가 있습니다. 그것을 찾는 프로그램을 작성하십시오." 프로젝트 오일러를 너무 많이했다고 생각합니다. - 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 등 모든 첫 번째 복합 번호를 반복 할 것입니다.

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 배 더 길 수 있습니다.

1
크레딧에 감사하지만 알고리즘은 내 것보다 훨씬 더 복잡합니다! PPCG에 오신 것을 환영합니다! :)
FryAmTheEggman

@FryAmTheEggman : 아이디어 주셔서 감사합니다! 고무적입니다.
Qualtagh

검사 복잡성에 대한 분석은 매우 흥미롭지 만 검색 적합성도 중요 할 것입니다. 나는 당신의 알고리즘이 큰 연약한 소수를 찾기 위해 (Emi 's와 비교하여) 소수에 대한 소수 테스트가 훨씬 덜 필요하다고 생각합니다. 또한 기본 라이브러리를 사용하여 우선 순위 테스트 속도를 높일 수 있습니다. Mpir.NET을 사용하고 있으며 취약한 프라임 번호를 확인하는 데 몇 분 정도 걸립니다.
Suboptimus Prime

13

파이썬 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 자리 숫자의 경우 동일한 프로그램을 사용하고 여러 코어의 작업 만 나눕니다.


3
"약 1 분 안에"-죄송합니다. 복수형 "버그"를보고해야합니다. : P
hichris123

밀러 라빈의 확률 적 특성은 저의 마지막 몇 가지 항목에 대해 저를 물고있었습니다. 다른 알고리즘으로도 확인하고 싶을 수도 있습니다.
John Meacham

끝에서 숫자를 제거하여 형성된 숫자가 복합인지 확인하는 이유는 무엇입니까? 왜 앞면에서 숫자를 제거하여 형성된 숫자를 확인하지 않습니까?
isaacg

1
내가 'for i'-loop에서 이것을 확인했기 때문입니다. 여기에 시작 부분에 9s를 추가하고 총체적으로 확인하십시오. 이 양식의 첫 번째 소수를 찾으면 처음에 9가 적은 모든 숫자가 소수가 아님을 알고 있습니다. 그리고 마지막에 9를 제거했는지 확인한 후에는 모든 숫자에 소수가 있으므로 소수가 아니기 때문에 중단합니다.
Jakube

아, 매우 영리합니다.
isaacg

7

파이썬 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은 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
당신이 찾은 소수는 연약하지 않습니다. Remove (n, 83,838) [처음 82 자리를 제외한 모든 항목 제거]를 호출하면 소수가됩니다.
Jakube

1
아, 감사합니다. 나는 너무 영리하려고 노력했다. 내가 더 많은 우선 순위 검사를 건너 뛰는 것으로 나타났습니다. 문제를 해결하려고합니다.
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 일 수 있습니다.

이러한 숫자의 경우 가능한 길이 만 (길이-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);
    }
}

첫 번째 답변을 확인하는 동안 이미 새로운 답변을 게시했습니다.)) 확인에는 이미 24 시간이 걸렸습니다. 정답 인 것 같습니다. Java의 BigInteger가 기본 구현보다 훨씬 느리다는 것을 믿을 수 없습니다. 나는 약 2 배, 3 배 또는 10 배 느리다고 생각했다. 그러나 몇 분에 대한 24 시간이 너무 깁니다.
Qualtagh

@Qualtagh 공평하게 말하면, 열등한 알고리즘으로 인해 10039 자리 숫자를 찾는 데 35 시간이 걸렸습니다. 현재 현재 프로그램은 6629 자리 숫자를 찾는 데 약 3 분, 28164 자리 숫자를 찾는 데 6 시간이 걸립니다.
Suboptimus Prime

첫 번째 대답은 맞습니다. 확인되었습니다! 확인에는 48 시간이 걸렸습니다. 그리고 나는 두 번째 대답을 확인하려고 시도하지 않을 것입니다)). BigInteger가 MPIR에 비해 왜 느린 지 궁금합니다. JVM / 네이티브 차이점 만 있습니까? "-server"플래그를 설정 했으므로 코드가 JIT 컴파일 될 것으로 예상합니다. 모듈 식 지수의 알고리즘은 다릅니다. Java와 MPIR 모두 2 <kupary-ary 슬라이딩 윈도우를 사용하지만 k = 3은 Java로 고정되어 있으며 MPIR은 지수의 크기에 따라 k를 선택합니다. MPIR이 여러 코어 또는 GPU 기능에서 병렬 계산을 사용합니까? Java의 BigInteger는 그렇지 않습니다.
Qualtagh '11

1
@Qualtagh 필자는 MPIR이 하나의 CPU 코어 만 사용하고 있다고 확신합니다. 멀티 스레딩을 직접 추가하여 쿼드 코어 CPU에서 거의 4 배 빠른 검색을 수행했습니다. MPIR과 Java BigInteger의 내부 구현을 비교하지는 않았지만 MPIR이 곱셈 및 모듈 식 나누기에 더 나은 알고리즘을 사용하고 있다고 생각합니다. 또한 64 비트 CPU에 더 적합 할 것입니다 ( 이 블로그 게시물 의 벤치 마크 참조 ).
Suboptimus Prime

2
MPIR은 실제로 단일 코어이며 GPU를 사용하지 않습니다. C와 어셈블러 코드의 고도로 최적화되고 미세 조정 된 믹스입니다. 이식성 때문에 C 만 사용하는 MPIR 버전이 있지만 C + ASM 버전이 훨씬 빠릅니다. MPIR.Net에 사용하는 MPIR 버전은 K8 (1 세대 x64) 명령 세트를 사용하는 C + ASM입니다. MPIR.Net을 모든 x64 PC에서 실행하기를 원했기 때문입니다. 이후의 명령어 세트의 버전은 내 암호 벤치 마크에서 눈에 띄게 빠르지는 않았지만 다른 작업에서는 물론 다를 수 있습니다.
존 레이놀즈

2

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)

마지막 3을 제외한 모든 것을 제거 할 수 있다고 생각합니다 ...
Sp3000

내가 5 마지막 3 그렇게 나눌 제거 할 경우 5로 끝나는
존 Meacham

2
아니오. 마지막 3 개가 남을 때까지 모든 것을 제거해야합니다.
Sp3000

1
@JohnMeacham 내 프로그램은 왼쪽에서 386 자리를 제거하면이 숫자가 소수로 바뀔 것을 제안합니다.
Suboptimus Prime

1
게시하기 전에 번호를 확인하십시오. 1276 자리 숫자에서 왼쪽 1256 자리를 제거하면 99999994999999999999가 표시됩니다. 이는 소수입니다.
Suboptimus Prime
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.