Я опытный программист, но плохо знаком с C. Я пытаюсь изучать C, чтобы я мог использовать библиотеку gmp для написания быстрых программ с большими целыми числами; в конце концов я намереваюсь написать части производительности моих программ в функциях C, которые вызываются через интерфейс сторонних функций из других языков. В качестве средства изучения и языка C, и библиотеки gmp я написал программу факторизации целых чисел polho rho, показанную ниже (да, я знаю, что это не лучшая возможная реализация polard rho, но она проста, и на данный момент я просто хочу начать). Моя программа компилируется правильно, но при запуске она умирает с сообщением «Ошибка сегментации». Я предполагаю, что это означает, что мои указатели где-то перепутались, но я этого не вижу. Вероятно, больше, чем один. Может кто-нибудь, пожалуйста, посмотрите на мою программу и скажите, где я ошибся? И указать на какие-либо проблемы со стилем или что-то еще, что я могу улучшить? Большое спасибо, Фил
/* rho.c -- pollard rho factorization
* usage: rho n -- prints factors of n then exits
* compile as gcc -lgmp -o rho rho.c */
#include <stdlib.h>
#include <stdio.h>
#include <gmp.h>
typedef struct list {
void *data;
struct list *next;
} List;
List *insert(void *data, List *next)
{
List *new;
if (! (new = malloc(sizeof(List))))
return NULL;
new->data = data;
new->next = next;
return new;
}
List *insert_in_order(void *x, List *xs)
{
if (xs == NULL || mpz_cmp(x, xs->data) < 0)
{
return insert(x, xs);
} else {
List *head = xs;
while (xs->next != NULL && mpz_cmp(x, xs->next->data) < 0)
{
xs = xs->next;
}
xs->next = insert(x, xs->next);
return head;
}
}
void rho_factor(mpz_t f, mpz_t n, long long unsigned c)
{
mpz_t t, h, d, r;
mpz_init_set_ui(t, 2);
mpz_init_set_ui(h, 2);
mpz_init_set_ui(d, 1);
mpz_init_set_ui(r, 0);
while (mpz_cmp_si(d, 1) == 0)
{
mpz_mul(t, t, t);
mpz_add_ui(t, t, c);
mpz_mod(t, t, n);
mpz_mul(h, h, h);
mpz_add_ui(h, h, c);
mpz_mod(h, h, n);
mpz_mul(h, h, h);
mpz_add_ui(h, h, c);
mpz_mod(h, h, n);
mpz_sub(r, t, h);
mpz_gcd(d, r, n);
}
if (mpz_cmp(d, n) == 0)
{
rho_factor(f, n, c+1);
}
else if (mpz_probab_prime_p(d, 25))
{
mpz_set(f, d);
}
else
{
rho_factor(f, d, c+1);
}
mpz_clears(t, h, d, r);
}
void rho_factors(List *fs, mpz_t n)
{
mpz_t f;
mpz_init_set_ui(f, 0);
while (! (mpz_probab_prime_p(n, 25)))
{
rho_factor(f, n, 1);
fs = insert_in_order(f, fs);
mpz_divexact(n, n, f);
}
mpz_clear(f);
insert_in_order(n, fs);
}
int main(int argc, char *argv[])
{
mpz_t f, n;
mpz_init_set_ui(f, 0);
List *fs = NULL;
if (argc<2)
{
printf("usage: rho n\n");
return 1;
}
mpz_init_set_str(n, argv[1], 10);
if (mpz_probab_prime_p(n, 25))
{
printf("%s\n", argv[1]);
return 0;
}
printf("%s", argv[1]);
rho_factors(fs, n);
while (fs != NULL) {
printf(" %s", mpz_get_str(NULL, 10, fs->data));
fs = fs->next;
}
return 0;
}
РЕДАКТИРОВАТЬ1: Благодаря Даниэлю Фишеру, я добился некоторого прогресса и больше не получаю ошибку сегментации. Код, показанный ниже, правильно печатает коэффициент 127, когда rho_factor вызывается с n = 1234567, но rho_factors возвращает нулевой список, поэтому с rho_factors все еще что-то не так. Я предполагаю, что проблема в том, что я не могу продолжать инициализировать одну и ту же переменную так, как я делаю, но я не знаю правильный способ сделать это. Каким-то образом мне нужно сделать копию каждого найденного фактора, а затем вставить эту копию в фс. Большое спасибо, Фил
/* rho.c -- pollard rho factorization
* usage: rho n -- prints factors of n then exits
* compile as gcc -lgmp -o rho rho.c */
#include <stdlib.h>
#include <stdio.h>
#include <gmp.h>
typedef struct list {
void *data;
struct list *next;
} List;
List *insert(void *data, List *next)
{
List *new;
if (! (new = malloc(sizeof(List))))
return NULL;
new->data = data;
new->next = next;
return new;
List *insert_in_order(void *x, List *xs)
{
if (xs == NULL || mpz_cmp(x, xs->data) < 0)
{
return insert(x, xs);
} else {
List *head = xs;
while (xs->next != NULL && mpz_cmp(x, xs->next->data) < 0)
{
xs = xs->next;
}
xs->next = insert(x, xs->next);
return head;
}
}
void rho_factor(mpz_t f, mpz_t n, long long unsigned c)
{
mpz_t t, h, d, r;
mpz_init_set_ui(t, 2);
mpz_init_set_ui(h, 2);
mpz_init_set_ui(d, 1);
mpz_init_set_ui(r, 0);
while (mpz_cmp_si(d, 1) == 0)
{
mpz_mul(t, t, t);
mpz_add_ui(t, t, c);
mpz_mod(t, t, n);
mpz_mul(h, h, h);
mpz_add_ui(h, h, c);
mpz_mod(h, h, n);
mpz_mul(h, h, h);
mpz_add_ui(h, h, c);
mpz_mod(h, h, n);
mpz_sub(r, t, h);
mpz_gcd(d, r, n);
}
if (mpz_cmp(d, n) == 0)
{
rho_factor(f, n, c+1);
}
else if (mpz_probab_prime_p(d, 25))
{
mpz_set(f, d);
}
else
{
rho_factor(f, d, c+1);
}
mpz_clears(t, h, d, r, NULL);
}
void rho_factors(List *fs, mpz_t n)
{
while (! (mpz_probab_prime_p(n, 25)))
{
mpz_t f;
mpz_init_set_ui(f, 0);
rho_factor(f, n, 1);
fs = insert_in_order(f, fs);
mpz_divexact(n, n, f);
}
insert_in_order(n, fs);
}
int main(int argc, char *argv[])
{
mpz_t f, n;
mpz_init_set_ui(f, 0);
List *fs = NULL;
if (argc<2)
{
printf("usage: rho n\n");
return 1;
}
mpz_init_set_str(n, argv[1], 10);
if (mpz_probab_prime_p(n, 25))
{
printf("%s is prime\n", argv[1]);
return 0;
}
rho_factor(f, n, 1);
printf("%s\n", mpz_get_str(NULL, 10, f));
printf("%s", argv[1]);
rho_factors(fs, n);
while (fs != NULL) {
printf(" %s", mpz_get_str(NULL, 10, fs->data));
fs = fs->next;
}
return 0;
}
EDIT2: Понял. Спасибо Даниэлю Фишеру. Окончательная версия показана ниже.
/* rho.c -- pollard rho factorization
* usage: rho n -- prints factors of n then exits
* compile as gcc -lgmp -o rho rho.c */
#include <stdlib.h>
#include <stdio.h>
#include <gmp.h>
typedef struct list {
void *data;
struct list *next;
} List;
List *insert(void *data, List *next)
{
List *new;
new = malloc(sizeof(List));
new->data = data;
new->next = next;
return new;
}
List *insert_in_order(void *x, List *xs)
{
if (xs == NULL || mpz_cmp(x, xs->data) < 0)
{
return insert(x, xs);
}
else
{
List *head = xs;
while (xs->next != NULL && mpz_cmp(x, xs->next->data) < 0)
{
xs = xs->next;
}
xs->next = insert(x, xs->next);
return head;
}
}
void rho_factor(mpz_t f, mpz_t n, long long unsigned c)
{
mpz_t t, h, d, r;
mpz_init_set_ui(t, 2);
mpz_init_set_ui(h, 2);
mpz_init_set_ui(d, 1);
mpz_init_set_ui(r, 0);
while (mpz_cmp_si(d, 1) == 0)
{
mpz_mul(t, t, t);
mpz_add_ui(t, t, c);
mpz_mod(t, t, n);
mpz_mul(h, h, h);
mpz_add_ui(h, h, c);
mpz_mod(h, h, n);
mpz_mul(h, h, h);
mpz_add_ui(h, h, c);
mpz_mod(h, h, n);
mpz_sub(r, t, h);
mpz_gcd(d, r, n);
}
if (mpz_cmp(d, n) == 0)
{
rho_factor(f, n, c+1);
}
else if (mpz_probab_prime_p(d, 25))
{
mpz_set(f, d);
}
else
{
rho_factor(f, d, c+1);
}
mpz_clears(t, h, d, r, NULL);
}
void rho_factors(List **fs, mpz_t n)
{
while (! (mpz_probab_prime_p(n, 25)))
{
mpz_t *f = malloc(sizeof(*f));
mpz_init_set_ui(*f, 0);
rho_factor(*f, n, 1);
*fs = insert_in_order(*f, *fs);
mpz_divexact(n, n, *f);
}
*fs = insert_in_order(n, *fs);
}
int main(int argc, char *argv[])
{
mpz_t f, n;
mpz_init_set_ui(f, 0);
List *fs = NULL;
if (argc<2)
{
printf("usage: rho n\n");
return 1;
}
mpz_init_set_str(n, argv[1], 10);
if (mpz_probab_prime_p(n, 25))
{
printf("%s is prime\n", argv[1]);
return 0;
}
printf("Factors of %s:", argv[1]);
rho_factors(&fs, n);
while (fs != NULL) {
printf(" %s", mpz_get_str(NULL, 10, fs->data));
fs = fs->next;
}
printf("\n");
return 0;
}