카테고리 없음
(정수론/C/GMP) 소수 구하는 함수 비교
미친토끼
2021. 9. 20. 23:20
C언어에서의 소수 관련 함수를 어떻게 gmp 라이브러리 함수로 바꿀 수 있는지 한번 살펴보자.
isPrime과 getPrimes 함수를 위주로 살펴보자.
#include "gmp.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <limits.h>
int isPrime(unsigned long num) {
unsigned long i, root_num;
root_num = (int)sqrt(num) + 1;
if (num <= 1) return 0; // 1 이하라면 소수 아님
if (num % 2 == 0) return 0; // 2의 배수라면 소수 아님
for (i = 3; i < root_num; i+=2)
if (num % i == 0)
return 0;
//printf("i = %lu", i);
return 1;
}
int isPrime2(mpz_t num){
mpz_t root_val, i, r;
mpz_inits(root_val, i, r, NULL);
if (mpz_cmp_ui(num, 1) != 1) // 1 이하면 소수 아님
return 0;
// 2로 나눠진다면 소수 아님, 리턴 0
mpz_fdiv_r_ui(r, num, 2); // 2로 나눠진다면 소수 아님, 리턴 0
if (mpz_cmp_ui(r, 0) == 0) return 0;
mpz_sqrt (root_val, num);
mpz_add_ui(root_val, root_val, 1);
mpz_set_ui(i, 3); // i = 3
for (; mpz_cmp(root_val, i);) { // root_val > i 인 동안
mpz_fdiv_r(r, num, i); // r = num % i
if (mpz_cmp_ui(r, 0) == 0) // num % i == 0
return 0;
// num이 2의 배수인 경우는 제외되었으므로 홀수만으로 나눔
mpz_add_ui(i, i, 2); // i = i + 2
}
return 1;
}
void getDivisor(mpz_t num) {
mpz_t root_val, i, q, r;
mpz_inits(root_val, i, q, r, NULL);
if (mpz_cmp_ui(num, 1) != 1) { // 1 이하면
printf("You must input a number lager than 1!");
return;
}
mpz_sqrt(root_val, num);
mpz_add_ui(root_val, root_val, 1);
mpz_set_ui(i, 2);
while (mpz_cmp(root_val, i) >= 0) { // root_val >= i 인 동안
mpz_fdiv_r(r, num, i);
if (mpz_cmp_ui(r, 0) == 0) { // r == 0
mpz_fdiv_q(num, num, i);
//재설정된 num의 sqrt값을 root_val로 설정
mpz_sqrt(root_val, num);
gmp_printf("%Zd, %Zd\n\n", i, num);
}
else
if (mpz_cmp_ui(i, 2) != 0) // i가 2가 아니라면
mpz_add_ui(i, i, 2); // i가 3 이상의 홀수이므로 2를 더하여 홀수로만 검사함
else
mpz_add_ui(i, i, 1); // i가 2라면 3으로 놓음
}
}
unsigned long getPrimes(unsigned long num) {
// 속도를 위해 소수 2는 제외하고 3부터 홀수만 검사함. 2외에는 짝수에 소수 없음.
for (unsigned long i = 3; i <= num; i+=2) {
if(isPrime(i)) //소수면 출력하거나 개수를 하나 올린다.
printf("%lu\n", i);
}
}
void getPrimes2(mpz_t num) {
mpz_t i, q, r;
mpz_inits(i, q, r, NULL);
mpz_set_ui(i, 3); // 소수 2는 나중에 추가. 홀수만 검사하기 위해서
while (mpz_cmp(num, i) >= 0) { // num >= i 인 동안
if(isPrime2(i))
gmp_printf("%Zd\t", i);
mpz_add_ui(i, i, 2); // i += 2
}
}
int main (int argc, char *argv[]) {
mpz_t n, m;
mpz_inits(n, m, NULL);
int MAX_NUM = 128; // 128자리수 아래는 각기 10^8, 10^16...
char *big_8 = "100000000";
char *big_16 = "10000000000000000";
char *big_32 = "100000000000000000000000000000000";
char *big_64 = "10000000000000000000000000000000000000000000000000000000000000000";
char *big_128 = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
char *big_256 = "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
char *big_512 = "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
char *big_1024 = "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
char *test_num = "14982300945943290918090909454983788547895985895893455426";
unsigned long num = ULONG_MAX; // 18446744073709551615
//mpz_set_str(n, big_8, 10);
//printf("%lu\n", ULONG_MAX);
//getPrimes2(n);
mpz_set_str(m, test_num, 10);
getDivisor(m);
//getPrimes(num);
//printf("%u\n", UINT_MAX);
return 1;
}
출력:
2, 7491150472971645459045454727491894273947992947946727713
1431690181, 5232382377407424196789580920854198603984134573