밀러 라빈 강력한 의사 프라임


16

음수가 아닌 정수가 주어지면, N모든 첫 번째 N소수에 강력한 의사 프라임 인 가장 작은 홀수 양의 정수를 출력하십시오 .

OEIS 시퀀스 A014233 입니다.

테스트 사례 (인덱싱)

1       2047
2       1373653
3       25326001
4       3215031751
5       2152302898747
6       3474749660383
7       341550071728321
8       341550071728321
9       3825123056546413051
10      3825123056546413051
11      3825123056546413051
12      318665857834031151167461
13      3317044064679887385961981

에 대한 테스트 사례 N > 13해당 값을 아직 찾지 못해 사용할 수 없습니다. 순서대로 다음 용어를 찾으면 OEIS에 제출하십시오!

규칙

  • N인덱스가 없거나 인덱스가없는 값을 선택할 수 있습니다 .
  • 솔루션이 언어의 정수 범위 내에서 표현할 수있는 값 ( N = 12부호없는 64 비트 정수까지) 에서만 작동하는 것이 허용 되지만, 언어가 임의의 길이의 정수를 지원한다는 가정하에 모든 입력에 대해 이론적으로 솔루션이 작동해야합니다.

배경

모든 긍정적 인 경우에도 정수 x형태로 기록 될 수 이상하다. 및 반복적으로 나눔으로써 계산 될 수 몫까지 (2)에 의해 더 이상 2로 나눌 수없는 그 최종 지수이고, 시간 (2)의 분할 개수이다x = d*2^sddsndsn .

양의 정수 n가 소수이면 Fermat의 작은 정리 는 다음과 같습니다.

페르마

어떤에서 유한 체 Z/pZ (여기서 p일부 소수이다)의 유일한 제곱근은 1있습니다 1-1(또는, 동등하게, 1그리고p-1 ).

우리는 다음과 같은 두 개의 문 중 하나가 소수에 대한 진실해야한다는 것을 증명하기 위해이 세 가지 사실을 사용할 수 있습니다 n(여기서 d*2^s = n-1r일부 정수에서이다 [0, s)) :

밀러 라빈 조건

밀러 - 라빈 소수 판별법은 상기 제 대우의 동작을 테스트하여,베이스가있는 경우 a, 상기 조건 모두 거짓이되도록하고 n프라임 아니다. 이 기지 a증인 이라고합니다 .

이제 모든베이스를 테스트 [1, n)하는 것은 계산 시간이 엄청나게 비쌉니다 n. Miller-Rabin 테스트에는 확률 필드에서 무작위로 선택된 일부만 테스트하는 확률 적 변형이 있습니다. 그러나 테스트는 단지 주요한 것으로 밝혀졌습니다.a 베이스 것으로 충분하므로 효율적이고 결정적인 방식으로 테스트를 수행 할 수 있습니다. 실제로 모든 소수의 염기를 테스트 할 필요는 없습니다. 특정 숫자 만 필요하며 해당 숫자는 소수에 대해 테스트 할 값의 크기에 따라 다릅니다.

소수의 소수 염기가 테스트되지 않으면 테스트에서 복합성이 입증되지 않는 홀수 복합 정수인 오 탐지가 발생할 수 있습니다. 구체적으로, a기수가 홀수의 합성 수의 합성 성을 증명하지 못하면, 그 수 를 base에 대한 강력한 의사 프라임 이라고합니다 a. 이 과제는 모든 N소수 에 대해 소수 소수 이하의 홀수 복합 수를 찾는 것에 관한 것입니다 (소수점이 소수에 해당하는 모든 소수 에 대해 유사 유사 수임이라고 말하는 것과 동일 함 N). .


1
샌드 박스 게시물 (현재 삭제됨)
Mego

규칙에서 허용하는 강력한 의사 우선 순위를 얻기 위해 1에서 모든 홀수 값을 테스트하는 알고리즘입니까?
user202729 2016 년

왜 그런지 모르겠습니다. 어떻게 생각하십니까?
Mego

대부분의 답변은 단순히 무차별적인 힘이 있기 때문에이 코드를 가장 빠른 코드로 만드는 것이 좋습니다 .
Neil A.

@NeilA. 나는 이것이 가장 빠른 코드보다 낫다는 것에 동의하지 않습니다. 다른 알고리즘이 아직 개발되지 않았고 PPCG가 그렇게 기대하지 않기 때문에 답변이 거의 확실하게 힘이 될 것이 사실이지만 코드 골프는 훨씬 간단하고 진입 장벽이 훨씬 낮습니다 (제출자 이후) 자신의 솔루션에 점수를 매길 수 있음), 모든 솔루션을 실행하고 점수를 매길 필요가 없으며 (거대한 런타임을 처리) 골프 문제로 충분히 흥미 롭습니다.
Mego

답변:


4

C, 349 295 277 267 255 바이트

N,i;__int128 n=2,b,o,l[999];P(m){i<N&&P(m<2?l[i++]=n:n%m?m-1:n++);}main(r){for(P(scanf("%d",&N));r|!b;)for(++n,b=i=N;i--&&b;){for(b=n-1,r=0;~b&1;b/=2)++r;for(o=1;b--;o=o*l[i]%n);for(b=o==1;r--;o=o*o%n)b|=o>n-2;for(o=r=1;++o<n;r&=n%o>0);}printf("%llu",n);}

stdin에서 1 기반 입력을받습니다. 예 :

echo "1" | ./millerRabin

확실히 곧 시퀀스에서 새로운 값을 발견하지는 않지만 작업을 완료합니다. 업데이트 : 이제 더 느려집니다!

  • Neil A의 답변에서 영감을 얻어 약간 더 빠르고 짧게 ( a^(d*2^r) == (a^d)^(2^r))
  • 이 챌린지에 대한 모든 솔루션이 홀수 임을 깨닫고 다시 느리게 진행 하므로 홀수 만 검사하도록 명시 적으로 강제 할 필요가 없습니다.
  • 이제 더 큰 숫자로 작업하는 동안 __int128보다 짧은 GCC를 사용하십시오 unsigned long long! 리틀 엔디안 머신에서도 printf는 %llu여전히 잘 작동합니다.

덜 축소

N,i;
__int128 n=2,b,o,l[999];
P(m){i<N&&P(m<2?l[i++]=n:n%m?m-1:n++);}
main(r){
    for(P(scanf("%d",&N));r|!b;)
        for(++n,b=i=N;i--&&b;){
            for(b=n-1,r=0;~b&1;b/=2)++r;
            for(o=1;b--;o=o*l[i]%n);
            for(b=o==1;r--;o=o*o%n)b|=o>n-2;
            for(o=r=1;++o<n;r&=n%o>0);
        }
    printf("%llu",n);
}

(구식) 고장

unsigned long long                  // Use the longest type available
n=2,N,b,i,d,p,o,                    // Globals (mostly share names with question)
l[999];                             // Primes to check (limited to 999, but if you
                                    // want it to be "unlimited", change to -1u)
m(){for(o=1;p--;o=o*l[i]%n);}       // Inefficiently calculates (l[i]^p) mod n

// I cannot possibly take credit for this amazing prime finder;
// See /codegolf//a/5818/8927
P(m){i<N&&P(m<2?l[i++]=n:n%m?m-1:n++);}

main(r){
    for(
        P(scanf("%llu",&N));        // Read & calculate desired number of primes
        r|!b;){                     // While we haven't got an answer:
        n=n+1|1;                    // Advance to next odd number
        for(b=1,i=N;i--&&b;){       // For each prime...
            for(d=n-1,r=0;~d&1;d/=2)++r; // Calculate d and r: d*2^r = n-1
            // Check if there exists any r such that a^(d*2^r) == -1 mod n
            // OR a^d == 1 mod n
            m(p=d);
            for(b=o==1;r--;b|=o==n-1)m(p=d<<r);
            // If neither of these exist, we have proven n is not prime,
            // and the outer loop will keep going (!b)
        }
        // Check if n is actually prime;
        // if it is, the outer loop will keep going (r)
        for(i=r=1;++i<n;r&=n%i!=0);
    }
    printf("%llu",n);               // We found a non-prime; print it & stop.
}

언급했듯이 1 기반 입력을 사용합니다. 그러나 n = 0 인 경우 9를 생성하며 관련 시퀀스 https://oeis.org/A006945 를 따릅니다 . 더 이상은 아닙니다. 이제 0에 달려 있습니다.

모든 n (적어도 출력이 2 ^ 64에 도달 할 때까지)에서 작동하지만 엄청나게 느립니다. 나는 n = 0, n = 1 및 ( 많은 대기 후 ), n = 2에서 확인했습니다.


나는 나의 해결책에 돌파구를 만들고, 당신은 단지 나를 위로한다. .. 멋지다!
Neil A.

@NeilA. 죄송합니다! 업데이트를 게시하기 전에 짧은 int 유형을 가지고 놀고있었습니다. 나는 당신이 어딘가에 2 바이트를 찾을 것이라고 확신합니다. 이것은 두 가지 다른 비 골프 언어라는 점을 고려할 때 놀랍도록 경쟁력이있는 것으로 판명되었습니다. D
Dave

3

파이썬 2, 633 465 435 292 282 275 256 247 바이트

0 인덱스

구현에 의문을 제기하고 새로운 것을 시도하십시오

함수에서 프로그램으로 변환하면 어떻게 든 바이트가 절약됩니다 ...

파이썬 2가 똑같은 일을하는 더 짧은 방법을 제공한다면, 나는 파이썬 2를 사용할 것입니다. 나눗셈은 기본적으로 정수이므로 2로 나누기가 더 쉬우 며 print괄호가 필요하지 않습니다.

n=input()
f=i=3
z={2}
a=lambda:min([i%k for k in range(2,i)])
while n:
 if a():z|={i};n-=1
 i+=2
while f:
 i+=2;d,s,f=~-i,0,a()
 while~d&1:d/=2;s+=1
 for y in z:
  x=y**d%i
  if x-1:
   for _ in[]*s:
    x*=x
    if~x%i<1:break
   else:f=1
print i

온라인으로 사용해보십시오!

파이썬은 다른 언어에 비해 악명 높다.

절대 정확성에 대한 시험 분할 테스트를 정의한 다음 의사 프라임이 발견 될 때까지 Miller-Rabin 테스트를 반복해서 적용합니다.

온라인으로 사용해보십시오!

편집 : 마침내 대답을 골프

편집하다 : min시험 분할 우선 성 테스트에 사용하고로 변경했습니다 lambda. 덜 효율적이지만 더 짧습니다. 또한 나 자신을 도울 수 없었고 두 개의 비트 연산자를 사용했습니다 (길이 차이 없음). 이론적으로는 (약간) 더 빨리 작동합니다.

편집 : 감사합니다 @Dave. 편집자가 나를 트롤했다. 탭을 사용하고 있다고 생각했지만 대신 4 개의 공백으로 변환되고 있습니다. 또한 거의 모든 Python 팁을 살펴보고 적용했습니다.

편집하다 : 0 인덱싱으로 전환하여 소수를 생성하여 몇 바이트를 저장할 수 있습니다. 또한 몇 가지 비교를 다시 생각했습니다.

편집하다 : 변수를 사용하여 for/else명령문 대신 테스트 결과를 저장했습니다 .

편집하다 : lambda매개 변수가 필요하지 않도록 함수 내부 로 이동했습니다 .

편집하다 : 바이트를 저장하기 위해 프로그램으로 변환

편집 : Python 2는 바이트를 절약합니다! 또한 입력을 다음으로 변환 할 필요가 없습니다.int


당신이 취급 한 방식으로 +1 a^(d*2^r) mod n!
Dave

파이썬에서 단일 공간 (또는 단일 탭) 들여 쓰기를 사용하여 많은 바이트를 절약 할 수 있다는 사실을 알고 있습니까?
Dave

@Dave : 들여 쓰기 수준 당 1 개의 탭을 사용합니다
Neil A.

IDE가 당신을 엉망으로 만들고 탭을 사용한다고 말하면서 공간을 절약한다고 생각합니다. 단일 공백으로 대체하면 311 바이트의 바이트 수를 얻습니다! 온라인으로 사용해보십시오!
Dave

@Dave : 알았어. 이상해. 고마워. 대답을 업데이트 할거야.
Neil A.

2

Perl + Math :: Prime :: Util, 81 + 27 = 108 바이트

1 until!is_provable_prime(++$\)&&is_strong_pseudoprime($\,2..nth_prime($_));$_=""

로 실행 -lpMMath::Prime::Util=:all(27 바이트 페널티, ouch)로 .

설명

기본적으로 무엇이든 내장 된 것은 Mathematica만이 아닙니다. Perl은 최초의 대규모 라이브러리 리포지토리 중 하나 인 CPAN을 보유하고 있으며 이와 같은 작업을위한 기성품 솔루션의 방대한 컬렉션이 있습니다. 불행히도 기본적으로 가져 오지 않거나 설치되지도 않습니다. 즉, 기본적으로 에서 사용하지 않는 것이 좋습니다 아니지만 그중 하나가 문제에 완벽하게 부합하는 경우 ...

우리는 소수가 아닌 하나를 찾을 때까지 연속적인 정수를 통과하지만 2에서 n 번째 소수 까지의 모든 정수 염기에 대해 강력한 의사 프라임입니다. 명령 행 옵션은 문제의 내장을 포함하는 라이브러리를 가져오고 암시 적 입력을 설정합니다 (한 번에 한 라인으로 설정; Math::Prime::Util정수의 개행을 좋아하지 않는 자체 내장 bignum 라이브러리가 있음). 이것은 $\어색한 구문 분석을 줄이고 출력이 암시 적으로 생성되도록하기 위해 (출력 라인 구분 기호)를 변수로 사용하는 표준 Perl 트릭을 사용 합니다.

우리 is_provable_prime는 확률 론적 (probabilistic) 프라임 테스트가 아닌 결정 론적 (deterministic) 테스트를 요청 하기 위해 여기 를 사용해야 합니다. (특히 확률 론적 프라임 테스트는 우선 Miller-Rabin을 사용했을 가능성이 높 으므로이 경우 신뢰할 수있는 결과를 기대할 수 없습니다!)

@Dada와 공동으로 Perl + Math :: Prime :: Util, 71 + 17 = 88 바이트

1until!is_provable_prime(++$\)&is_strong_pseudoprime$\,2..n‌​th_prime$_}{

-lpMntheory=:all(17 바이트 페널티)로 실행하십시오 .

이것은 내가 알지 못했던 몇 가지 Perl 골프 트릭을 사용합니다 (명확하게 Math :: Prime :: Util에는 약어가 있습니다!)는 알고 있지만 사용하지는 않았습니다 ( 암시 적으로 모든 라인이 아니라 암시 적으로 한 번 }{출력 ). 또는 알고 있었지만 어떻게 든 잘못 적용되었습니다 (함수 호출에서 괄호 제거). 이것을 지적 해 준 @Dada에게 감사드립니다. 그 외에는 동일합니다.$\"$_$\"


물론 골프 같은 언어가 와서 나머지를 능가합니다. 잘 했어!
Neil A.

ntheory대신 사용할 수 있습니다 Math::Prime::Util. 또한 }{대신에 ;$_=""괜찮을 것입니다. 그리고 1함수 호출 후의 공백 과 괄호를 생략 할 수 있습니다 . 또한 &대신에 작동합니다 &&. 88 바이트를 제공해야합니다.perl -Mntheory=:all -lpe '1until!is_provable_prime(++$\)&is_strong_pseudoprime$\,2..nth_prime$_}{'
Dada

에 대해 완전히 잊었습니다 }{. (이상하게도, 나는 괄호를 기억했지만 Perl에서 골프를 뛴 후 오랜 시간이 지났고 그것을 떠나는 규칙을 기억하지 못했습니다.) 나는 ntheory약어에 대해 전혀 몰랐습니다 .
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.