xrange() Alternative mit Long Int?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
C4S3
User
Beiträge: 292
Registriert: Donnerstag 21. September 2006, 10:07
Wohnort: Oberösterreich

Hallo!

Noch immer kämpfe ich darum, die Sache mit den Primfaktoren zu verstehen. Grundsätzlich läuft es gut und ich glaube am richtigen Weg zu sein.
Ich habe die Hinweise in diesem Thread dankbar angenommen, mich so gut es mir möglich war mit der Materie beschäftigt und versuche nun, das ganze auch umzusetzen.

Meine Tests verliefen bisher gut, bis ich Zahlenwerte erreicht habe, die größer als "maxint" sind.

In meiner Funktion verwende ich mehrere Male xrange(). Wenn aber einer der Werte nun größer als "maxint" ist, bekomme ich natürlich:

Code: Alles auswählen

OverflowError: long int too large to convert to int
Kurzum: wie kann ich meine Funktion so gestalten, dass ich auf xrange verzichen kann?

Ich habe versucht die Anleitung auf Wikipedia zum Sie des Eratosthenes so gut wie mir möglich war, in Python umzusetzen.

Nur mit den großen Zahlen (Zielwert: 600851475143) gibt es nun Probleme.

Wie kann ich das umgehen?
Danke.

Code: Alles auswählen

#! /python25/python.exe
# coding: utf-8

"""Primenumbers and Primefactor.

Based on an idea to solve "Project Euler" problems."""

def getPrimes(N):
    """
    getPrimes(N) -
    Returns a list with prime numbers within
    the given value 'N'.

    Algorithm based on the one explained on
    http://de.wikipedia.org/wiki/Sieb_des_Eratosthenes
    'The sive of Erathosthenes'
    """
    done = {}
    i = 2

    for i in xrange(2, N+1):
        done[i] = False

    i = 2
    while i*i <= N+1:
        if not done[i]:
            j = i*i
            for j in xrange(j, N+1, i):
                done[j] = True
        i += 1

    l = []
    i = 2
    for i in xrange(i, N+1, 1):
        if not done[i]:
            l.append(i)
    return l




if __name__ == "__main__":

    print getPrimes(30)
    print getPrimes(37)
    print getPrimes(1024)
    print getPrimes(600851475143)
Gruß!
lunar

Du musst "xrange()" eben durch eine manuelle Zählschleife ersetzen.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

oder eine in Python geschriebene Variante...

Code: Alles auswählen


def lxrange(start, stop, step):
    i = start
    while i < stop:
        yield i
        i += step
BlackJack

@C4S3: *Hust* Überleg doch mal ein bisschen wieviel Speicher und Rechenzeit das bräuchte.

Wenn für jede der Zahlen im Schnitt eine Mikrosekunde gebräucht würde, rechnet das Programm fast eine Woche.

So lange wird es aber gar nicht laufen, denn selbst wenn man für `done` eine Liste nimmt, sind alleine die Zeiger auf die Wahrheitswerte zusammen schon 4,8 Terabyte gross. Wobei ich jetzt von einem 64-Bit-System ausgehe, denn bei 32-Bit reicht der Adressraum für einen Prozess überhaupt nicht aus.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

C4S3 hat geschrieben:In meiner Funktion verwende ich mehrere Male xrange(). Wenn aber einer der Werte nun größer als "maxint" ist, bekomme ich natürlich:

Code: Alles auswählen

OverflowError: long int too large to convert to int
Kurzum: wie kann ich meine Funktion so gestalten, dass ich auf xrange verzichen kann?
Das Problem ist nicht xrange(), sondern das, was du da vorhast: Dafür reicht weder die Rechenzeit noch der Speicher auf deinem Rechner aus ...

Ich zitiere mich mal selbst aus dem Thread, auf den du verweist (wäre IMHO auch sinnvoll gewesen, keinen neuen Thread aufzumachen, sondern den anderen weiterzuführen):
numerix hat geschrieben:Zunächst ermittelst du alle Primzahlen, die als Primfaktoren in Frage kommen (welche "in Frage kommen", verrate ich jetzt mal noch nicht; kannst ja mal drüber nachdenken).
Die Betonung liegt auf dem "in Frage kommen" - darüber hast du noch nicht genug nachgedacht. Tu das und du kommst der Lösung näher. :wink:
Benutzeravatar
C4S3
User
Beiträge: 292
Registriert: Donnerstag 21. September 2006, 10:07
Wohnort: Oberösterreich

:shock:
Ich bin jetzt erschüttert.
Insgeheim war ich schon stolz auf mich, weil die Sache bis zu einer gewissen Größe ja wunderbar funktioniert hatte.

Die Funktion nachzubauen, wäre also technisch Möglich (siehe While-Schleife oben), aber löst das eigentliche Problem dahinter nicht.

@BlakJack: :oops:
Ich hatte das irgendwie nicht beachtet. Nur mal so aus Interesse: kann man, bzw. wie kann man herausfinden, wie der Speicher genutzt wird, wie groß die Objekte sind, etc.?
numerix hat geschrieben:wäre IMHO auch sinnvoll gewesen, keinen neuen Thread aufzumachen, sondern den anderen weiterzuführen
Naja, ich dachte, DIES hier ist ein Problem mit dem Verständnis von Python und das andere war wirklich ein Offtopic Mathematikproblem. Dass ich am Ende wieder bei meinen dürftigen Kenntnissen der Mathematik scheitern würde, ahnte ich noch nicht, als ich diesen Beitrag verfasste. Sorry.
numerix hat geschrieben:
numerix hat geschrieben:Zunächst ermittelst du alle Primzahlen, die als Primfaktoren in Frage kommen (welche "in Frage kommen", verrate ich jetzt mal noch nicht; kannst ja mal drüber nachdenken).

Die Betonung liegt auf dem "in Frage kommen" - darüber hast du noch nicht genug nachgedacht. Tu das und du kommst der Lösung näher. Wink
Ich seh schon, für mich ist ne Abendschule fällig. B-Matura würde man hier in Österreich dazu sagen...
:cry:

Was mich jetzt ein wenig stutzig macht:
Ich hatte mein "Problem" in zwei Teile zerlegt:
  • a) das Herausfinden aller Primzahlen zwischen 2 und N
  • b) die Primfaktoren von N
Bevor ich mich mit den Primfaktoren auseinandersetzen konnte, musste ich mich vorher mit Eratosthenes' Sieb auseinandersetzen. Ich nahm an, wenn ich erst mal alle Primzahlen bis N hätte, könnte ich mir noch Gedanken machen, welch ich vlt. nicht benötige.

Ich hatte die Funktion so gut es ging implementiert und merke nun, dass ich wieder am Start stehe, weil meine Version mit großen Zahlen einfach nicht umgehen kann.
Es wäre nun auch noch egal, welche Sprache ich dazu wählen würde, ich müsste mir unweigerlich um den Speicherverbrauch und die Rechenzeit Gedanken machen.


Mir kommt vor, als würde ich mich im Kreis drehen...
Gruß!
BlackJack

@C4S3: Im Grunde ist die Optimierung auch schon einmal im Sieb-Algorithmus enthalten. Falls mir der Tipp erlaubt ist: Mit der Menge der Primzahlen, die Du im letzten Aufruf erzeugen wolltest, könntest Du Zahlen bis 361022495181519146870449 zerlegen. :-)

Im Artikel wird ein Array verwendet, was in etwa einer Liste in Python entspricht. Warum hast Du daraus ein Dictionary gemacht?

Ansonsten sollte man aus der ``while``-Schleife eine ``for``-Schleife machen, denn die Anzahl der benötigten Durchläufe ist ja beim Schleifeneintritt fest. Und insgesamt kann man das auch ein wenig "pythonischer" schreiben. Zeile 27 würde ich eleminieren und das ``i * i`` direkt einsetzen.

Für so richtig grosse Zahlen kann man das Sieb so umgestalten, dass es dynamisch von unten wächst, und "live" jede gefundene Primzahl ``yield``en. Wenn in der richtig grossen Zahl nicht zufällig auch grosse Primfaktoren stecken, bekommt man die auch recht schnell in handlichere Teile zerlegt. Deine Riesenzahl ist zerlegt nämlich "nur": 71 * 839 * 1471 * 6857.
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Für wirklich große Zahlen würde ich aber wahrscheinlich keinen Siebalgorithmus mehr nehmen. Dazu gibt es eine ganze Reihe weiterer Verfahren die auch z.T. gar nicht mal so schwierig zu implementieren sind. Hinweise darauf findest du hier:http://de.wikipedia.org/wiki/Primzahltest. Ich glaub ich hab damals mal den Fermatschen Primzahltest und den Miller-Rabin-Test unmgesetzt.
BlackJack

Für wirklich grosse geht's halt einfach nicht. Wir reden hier von Primfaktorzerlegung, nicht darum zu testen ob *eine* grosse Zahl *vielleicht* prim ist. Denn der Miller-Rabin kann nur das Gegenteil mit Bestimmtheit feststellen.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

die richtig grossen primzahlen werden mit dem lucas/lehmer test gesucht.
(aber nicht mit python :) )

Code: Alles auswählen

def lucas_lehmer(p):
    s = 4
    m = (2 ** p) - 1
    for i in range(0, p - 2):
        s = ((s * s) - 2) % m
    
    return (s == 0)
kannst du ja mal vergeichen mit deinem sieb. (macht zwar wenig sinn...)

achtung: hier kannst du nur primzahlen der form 2^p - 1 finden, du musst der funktion ein p übergeben.

mit p = 3 zb: 2^3 - 1 = 7 --> prim.
http://www.kinderpornos.info
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Wir reden hier von Primfaktorzerlegung, nicht darum zu testen ob *eine* grosse Zahl *vielleicht* prim ist.
:oops: uups... zu flüchtig gelesen...
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

C4S3 hat geschrieben:Ich bin jetzt erschüttert.
Insgeheim war ich schon stolz auf mich, weil die Sache bis zu einer gewissen Größe ja wunderbar funktioniert hatte.
Kannst auch stolz sein, bist ja auf dem richtigen Weg! Nicht die Geduld verlieren und an einer Sache dran bleiben - das ist wichtig.
C4S3 hat geschrieben:Dass ich am Ende wieder bei meinen dürftigen Kenntnissen der Mathematik scheitern würde, ahnte ich noch nicht, als ich diesen Beitrag verfasste.
Nee, viel Mathematik brauchst du dafür nicht. Das ist eher eine Frage des noch gründlicher darüber Nachdenkens.

Nimm mal als Beispiel die 121. Welches ist die größte Zahl, die als Primfaktor in Frage kommt und warum ist das so? Wenn du das klar hast, dann weißt du auch, bis zu welchem n du das Sieb laufen lassen musst, um alle potentiellen Primfaktoren von 600851475143 zusammen zu haben. Und wenn du dann den Eratosthenes nicht ganz schlecht implementiert hast, dann ist der damit in ein paar Sekunden fertig.

Für diese konkrete Aufgabe (bei der gegebenen Zahl) reicht der Eratosthenes aus - andere Primzahl-Verfahren brauchst du dafür nicht.

Wenn du vor hast, bei Euler noch weitere Aufgaben zu lösen, dann lohnt es sich auf jeden Fall, sich einmalig Zeit für eine gute Implementierung des Eratothenes zu nehmen, weil es noch einige weitere Aufgaben gibt, wo er dir gute Dienste leistet.
Antworten