C Faktorisierungsmethode von Dixon / Project Euler

Elcrian

Commander
Registriert
Feb. 2008
Beiträge
2.493
Hallo zusammen,

ich versuche aktuell für Project Euler die Faktorisierungsmethode von Dixon in C zu programmieren, scheitere aber etwas an den Details und dem Verständnis, da sich die Beschreibungen des Algorithmus' im Netz etwas zu widersprechen scheinen.

Mein Verständis war bisher folgendes:

1) Bestimmte Faktorbasis k bis exp(0.5 * sqrt(log(N) * log(log(N))))
--> Ich nutze dazu das Sieb von Erathosthenes, da ich den Ranz für andere Euler-Probleme ohnehin geschrieben habe
2) Erzeuge x_i als ceil(sqrt(N)) < x_i < N mit einer linearen Folge x++ und faktorisiere als a_i % x_i^(2) % N
3) Wenn pk-glattes a_i (--> der größte Primfaktor von pk is < a_i) gefunden, speichere [x_i,a_i]
4) Speichere die Faktoren von a? Danach macht weder Wiki noch die anderen Artikel für mich viel Sinn...

Algorithmus:
Code:
long dixon(int N) {
	int pk = exp(0.5 * sqrt(log(N) * log(log(N))));
	int* P = getAllFromSieveOfEratosthenes(pk); // factor base
	// Try to get x_i as ceil(sqrt(N)) < x_i < N and factorize as
	// a_i % x_i^(2) % N. (de.wiki)
	int x = 1, i = 0, j = 0;
	int a = 0;
	int y[N][2];
	int* e[N];
	printf("N: %i, pk: %i \n",N,pk);
	for (x = ceil(sqrt(N)); x <= N; x++) {
		a = (int) pow(x, 2) % N;
		x++;
		if (isBSmooth(a, pk)) {
			y[i][0] = x; // x
			y[i][1] = a; // p(x)
			e[i] = getPrimeFactors(a); // factors of a
			i++;
		}
	}
}

Andere Methoden:
Code:
/**
 * Checks if x is B-smooth
 * e.g. isBSmooth(1620,5) == true
 * 1,620 has prime factorization 2^2 × 3^4 × 5; therefore 1,620 is
 * 5-smooth because none of its prime factors are greater than 5
 */
bool isBSmooth(long x, int B) {
	int* P = getPrimeFactors(x);
	int i;
	for (i = sizeof(P) / sizeof(int); i >= 0; i--) {
		if (*(P + i) > B)
			return false;
	}
	//free(P);
	return true;
}

/*
 * https://stackoverflow.com/questions/23287/largest-prime-factor-of-a-number
 * Runs O(sqrt(n))
 * @param n positive integer
 * @return All the prime factors of a positive integer n
 */
int* getPrimeFactors(int n) {
	int* factors = calloc(ceil(0.25 * n), sizeof(int));
	int d = 2, i = 0, ct = 0;
	while (n > 1) {
		while (n % d == 0) {
			*(factors + i) = d;
			n /= d;
			i++;
			if(d != 0) ct++;
		}
		d++;
		if (d * d > n) {
			if (n > 1) {
				*(factors + i) = n;
				i++;
				if(n != 0) ct++;
			}
			break;
		}
	}
	// this counts as dynamic array, right?
	int* fact = calloc(ct,sizeof(int));
	memcpy(fact,factors,ct);
	//free(factors);
	return fact;
}
/*
 * This is horrible style. I copied this from Problem7.c b/c I wanted to avoid
 * tripple-overloading
 * @returns all Primes <= limit
 */
int* getAllFromSieveOfEratosthenes(int limit) {
	limit--;
	const int UNMARKED = 1;
	const int MARKED = 0;
	long i = 0, j = 0, counter = 0;
	long size = limit * 100; // Not exactly accurate. Might need some refining
	int* primes = malloc(size * sizeof(int));
	int* res = malloc(size * sizeof(int));
	int lastPrime = 2;

	// start at 2. Set all as prime
	for (i = lastPrime; i < size; i++) {
		// this kills 32bit-OS, since j*i will exceed 2^(32)-1 pretty quickly
		*(primes + i) = UNMARKED;
	}
	*(primes + 2) = MARKED;
	i = lastPrime;
	// Starting from p^(2), enumerate its multiples by counting to n in increments of p, and mark them in the list
	do {
		for (j = i; (i * j) < size; j++) {
			*(primes + j * i) = MARKED;
		}
		// Find the first number greater than p in the list that is not marked
		for (j = lastPrime; j < size; j++) {
			if (j > lastPrime && *(primes + j) == UNMARKED) {
				// Let p now equal this new number
				i = lastPrime = j;
				// add to result
				*(res + counter) = i;
				// Increment prime-count
				counter++;
				break;
			}
		}
	} while (counter < limit);
	free(primes);
	return res;
}

Eine meine Quellen meinte folgendes:
/*
* the exponents of the prime factors are converted into an exponent vector mod 2.
* For example, if the factor base is {2, 3, 5, 7} and the p(x) value is
* 30870, we have:
* 30870 = 2^1 * 3^2 * 5^1 * 7^3
*/
Da mein Ansatz:
Code:
	int bf = 0, ct = 0, imax = 0;
	int emax = sizeof(e) / sizeof(int);
	int* expMat[emax];
	for (i = 0; i < emax; i++) {
		imax = sizeof(e[i]) / sizeof(int);
		int v[imax][2];
		*(expMat+i) = v;
		for (j = 0; j < imax; i++) {
			// if the current exponent is still being counted, increment
			if(*(e[i]+i) == bf) {
				ct++;
			}
			// re-set the buffer and store the value in the exponent vector
			else {
				v[i][0] = bf;
				v[i][1] = ct;
				bf = *(e[i]+i);
				ct = 0;
			}
		}
	}
Aber, ganz offen gesagt: Weder klappt das, noch verstehe ich den Zusammenhang hier...

Folgende Quellen:
https://en.wikipedia.org/wiki/Dixon's_factorization_method
https://de.wikipedia.org/wiki/Dixons_Faktorisierungsmethode
http://nptel.ac.in/courses/106103015/26
http://mathworld.wolfram.com/DixonsFactorizationMethod.html
http://people.mpi-inf.mpg.de/~csaha/lectures/lec19.pdf
http://www.cse.iitk.ac.in/users/manindra/CS681/2005/Lecture21.pdf

Daher: Kann mir jemand verraten wie ich bei meiner Auflistung an Punkt 4) weiter komme? Ich stehe wirklich auf'm Schlauch...

Disclaimer: Ich habe weder Informatik noch Mathe studiert und mache das privat aus Spaß an der Freude. Also bitte keine "Das ist doch sooo offensichtlich!"-Posts. ;) Und meine leider nicht mehr vorhandenen Hausaufgaben macht auch keiner..

Allgemeine Frage: Die auskommentierten "free()" Aufrufe produzieren Fehler - warum eigentlich? C ist mir immer noch ein Rätsel...
 
Zuletzt bearbeitet:
Elcrian schrieb:
Allgemeine Frage: Die auskommentierten "free()" Aufrufe produzieren Fehler - warum eigentlich? C ist mir immer noch ein Rätsel...

Für so eine Frage bietet sich valgrind an.

Du benutzt auf jeden Fall den sizeof-Operator falsch. sizeof(Zeiger) kann dir nicht sagen, wie groß das Array ist, auf das gezeigt wird. Es wird dir die Größe des Zeigers selbst geben, also 4 für eine 32-Bit Adresse bzw. 8 bei 64bit.

free() lässt ein Programm abstürzen, wenn man interne Daten kaputt gemacht hat, die zur Freigabe des Speichers notwendig sind. Andere Möglichkeiten sind double free und use after free. Ich gehe nach kurzem Überfliegen davon aus, dass deine falsche Benutzung von sizeof dazu führt, dass du auf Speicher zugreifst, von dem du die Finger lassen sollst und free() dann das Handtuch wirft.

Habe aber wirklich nur grob drüber geguckt und könnte total daneben liegen.
 
Zurück
Oben