Bitte Kritik zu meinem Code

Registriere dich jetzt, um exklusive Vorteile zu genießen! Als registriertes Mitglied kannst du Inhalte herunterladen und profitierst von einem werbefreien Forum.
Mach mit und werde Teil unserer Community!
  • Hi,

    ich habe leider jetzt erst gesehen, dass du ein paar Punkte von Dennis89 aufgegriffen hast. Ich lasse sie oben trotzdem mal stehen.

    Bei `intervall_pruefen()` stimmt die Beschreibung nicht. Da steht für alle ungeraden `h`, aber wenn `ausgabe` den Wert `True` hat, werden auch die geraden `h` geprüft. Was stimmt denn nun? Der Code oder die Dokumentation?


    `ausgabe` hat Dennis89 ja bereits angesprochen. Im Code ist dann auch noch mal ein Kommentar der nötig ist, weil das so ein bisschend verwirrend ist. Kann es sein das in beiden Fällen nur die ungeraden `h` bearbeitet werden sollen? Dann steht da fast der gleiche Code doppelt. Der sollte da nur einmal stehen und nur das `print()` sollte bedingt ausgeführt werden.

    Ja, da ist mir was durcheinander gegangen. Es sollten erstmal nur die ungeraden h geprüft werden, unabhängig von ausgabe.


    Es sieht auch so ein bisschen danach aus, als wenn hier keine selbst gebastelte Lösung, sondern vielleicht Logging verwendet werden sollte.

    Was ist das?

    `exp` in `bosma()` wird auch berechnet wenn das gar nicht verwendet wird. Das sollte in den entsprechenden ``if``-Zweig wandern.

    Verstehe ich.


    Auch die anderen Punkte habe ich größtenteils nachvollzogen.

    Eine Frage habe ich zu raise ValueError. Ich verstehe den Hintergrund, eine Funktion sollte immer die gleiche Art von Werten zurückgeben.

    Wenn ich nun aber sagen wir 10.000 Koeffizienten h überprüfe, dann kann es sein, dass nur ein einziger nicht mit der vorgelegten Liste von Primzahlen überprüft werden kann, alle anderen aber schon. Wenn dann ein ValueError auftritt, wird die komplette Berechnung doch sofort abgebrochen. Ich würde aber gerne auch nachhalten, wieviele Kandidaten ich nicht berechnen konnte.


    Danke sehr! Ich gehe nun weiter den Code durch.

  • neuernutzer Logging ist das Protokollieren von Ereignissen, unter anderem üblicherweise mit verschiedenen Leveln über die man steuern kann was ausgegeben wird und was nicht. Da gibt's Bibliotheken für. In der Python-Standardbibliothek das `logging`-Modul oder auch das externe `loguru`. Letzteres nehme ich ganz gerne für Programme und Dienste.


    Was wäre denn so schlimm daran das ``if`` in der Schleife zu haben? Was passieren kann wenn man der Code stattdessen zweimal schreibt oder kopiert hast Du ja gesehen: Wenn man dabei Fehler macht, dann machen die beiden ”Kopien” nicht mehr das gleiche. Redundanter Code macht mehr Arbeit beim Schreiben und beim Verändern, und ist fehleranfälliger.


    Ob bei einer Ausnahme die komplette Berechnung abgebrochen wird, hängt davon ab was der Code der das aufruft mit der Ausnahme macht. Bei -1 funktioniert der Indexzugriff nicht, da wäre ein `IndexError` die Folge, also nichts gewonnen. Und bei dem `None` ignoriert der Code Argumente mit denen `jacobisymbol()` gar nicht hätte aufgerufen werden dürfen, was im Grunde ja ein Programmierfehler ist, der dann einfach ignoriert wird. Und wenn man diese Fälle auch irgendwie aufzeichnen will, müsste man Code schreiben der explizit auf die -1 oder das `None` prüft. Wenn man das macht, könnte man an der Stelle genau so gut Code schreiben der statt einen besonderen, magischen Rückgabewert zu prüfen, die Ausnahme behandelt. Ausnahmen wurden erfunden damit man keine magischen Fehlerwerte braucht, und die immer überall prüfen muss, oder falls man das nicht tut, mit falschen Werten weitergearbeitet wird, als wäre nichts passiert.

    „Eat the rich — the poor are full of preservatives.“ — Rebecca ”Becky” Connor, The Connors

  • neuernutzer


    Was wäre denn so schlimm daran das ``if`` in der Schleife zu haben? Was passieren kann wenn man der Code stattdessen zweimal schreibt oder kopiert hast Du ja gesehen: Wenn man dabei Fehler macht, dann machen die beiden ”Kopien” nicht mehr das gleiche. Redundanter Code macht mehr Arbeit beim Schreiben und beim Verändern, und ist fehleranfälliger.

    "Schlimm" ist es nicht. Aber bei sovielen Werten dauert es doch wirklich länger, jedesmal die if-Abfrage durchzuführen. Dabei sind 10.000 viel zu wenig, sagen wir mal 2^20 Werte.
    Jedenfalls war das mein Gedanke dahinter.

  • Naja, das fällt IMHO in die Kategorie „premature optimization“. Wie gesagt sieht man ja was passieren kann wenn man wegen so etwas Code zweimal schreibt — der muss dann nicht das gleiche machen wenn man nicht aufpasst. Und wenn man hier irgendwie Probleme mit der Geschwindigkeit hat, dann ist nicht ein einzelnes ``if`` das wirkliche Problem, sondern dass das in Python geschrieben ist. Solche Mikrooptimierungen sollte man nur machen wenn man da auch Messungen macht ob und was das am Ende tatsächlich bringt. Insbesondere wenn dadurch der Code fehleranfälliger wird.

    „Eat the rich — the poor are full of preservatives.“ — Rebecca ”Becky” Connor, The Connors

  • Naja, das fällt IMHO in die Kategorie „premature optimization“. Wie gesagt sieht man ja was passieren kann wenn man wegen so etwas Code zweimal schreibt — der muss dann nicht das gleiche machen wenn man nicht aufpasst. Und wenn man hier irgendwie Probleme mit der Geschwindigkeit hat, dann ist nicht ein einzelnes ``if`` das wirkliche Problem, sondern dass das in Python geschrieben ist. Solche Mikrooptimierungen sollte man nur machen wenn man da auch Messungen macht ob und was das am Ende tatsächlich bringt. Insbesondere wenn dadurch der Code fehleranfälliger wird.

    Das sehe ich ein. Python ist für den Zweck der Statistik sicher nicht die richtige Wahl. Für meine Zwecke ist es allerdings ausreichend. Trortdem möchte ich python verstehen und das beste rausholen.


    Als nächstes stellt sich mir die Frage, ob ich das nun paralleliseren kann.

    Das plotten kann erstmal in den Hintergrund rücken. Ich habe nun über den Nachmittag die Exponenten bis einschließlich 26 überprüfen können und die Ergebnisse pro Exponent in einer Datei abgelegt. Diese kann ich nun laden und plotten.

    Jetzt frage ich mich, ob ich nicht bei meinen 4 Kernen jeweils 4 Exponenten gleichzeitig überprüfen kann. Das war der Hintergrund für den ersten Thread.

    Lohnt es sich, das hier zu machen? Wie erkenne ich das?
    Mit "Lohnen" meine ich nicht die allgemeine Fragestellung, ob python oder mein Rechner überhaupt schnell genug ist dafür, sondern prinzipiell.

  • neuernutzer Habe meinen Code jetzt tatsächlich mal ausprobiert. So viele Primzahlen mussten ja gar nicht generiert werden um das mal zu testen.


    Und es läuft in die Ausnahme bei der Jacobisymbol-Funktion, weil die erste Primzahl, die 2, die Bedingung nicht erfüllt nicht gerade zu sein:

    Nach dem laden der Primzahlen könnte man die 2 einfach entfernen, dann läuft man nicht mehr in dieses Problem.


    Wenn man sich anschaut wie man das am besten parallelisieren kann, fällt auf, das die Aufteilung des Codes auf Funktionen ungünstig ist. Eine Funktion sollte nur eine in sich geschlossene Sache machen. `plotten()` sollte Ergebnisse plotten, und nicht vorher auch noch die Berechnung machen. Ich habe das mal innerhalb der Funktion getrennt, das erst die Ergebnisse berechnet, und dann geplottet wird. Dann kann man statt der Schleife oder „list comprehension“ welche die Ergebnisse berechnet, `map()` beziehungsweise `starmap()` von `multiprocessing.Pool` verwenden und mehrere Exponenten parallel verarbeiten lassen.


    „Eat the rich — the poor are full of preservatives.“ — Rebecca ”Becky” Connor, The Connors

  • neuernutzer Habe meinen Code jetzt tatsächlich mal ausprobiert. So viele Primzahlen mussten ja gar nicht generiert werden um das mal zu testen.

    Das ist richtig, statistisch braucht man nur sehr wenige und auch nur sehr kleine. Leider ist das noch nicht bewiesen.


    Zu deiner weiteren Anmerkung: Mit map habe ich mich noch nicht beschäftigt, das schaue ich mir aber an.

    Ich hatte gestern abend den Code auch nochmal leicht geändert, sodass "plotten" jetzt wirklich nur den Vektor plottet, den es bekommt. Hier erstmal der ganze Code, Änderungen sind ab Zeile 113:

    Kommentiere ich die letzten drei Zeilen ein und die Zeilen 118 bis 134 aus, kann ich die einzelnen Dateien plotten lassen. So hatte ich mir das gewünscht.


    Möglicherweise ist meine Vorstellung von Parallelisierung falsch, aber kann ich nun nicht sagen: Kern 1 prüft die Exponenten 1,5,9..., Kern 2 prüft 2,6,10... und so weiter?

  • neuernutzer Diese Aufteilung willst Du nicht selbst machen. Da kümmert sich der `Pool` drum, dass die Prozesse ausgelastet sind.

    Echt schade. Ich hatte wirklich gehofft auf
    "Prüfe wieviele Kerne vorhanden sind, dann verteile entsprechend dieser".


    Und dieser "Pool", ist das der, den du auch in deinem vorherigen Beitrag bereits im Code angebracht hast?


    Edit: Ah, jetzt habe ich den Code bei mir mal laufen lassen. Das ist schon auf die Kerne verteilt.
    Hab ich mich leider wieder alles viel zu einfach vorgestellt.

    Wenn ich das richtig sehe (anhand des System Monitors), dann nimmt sich jetzt einfach ein Kern, der gerade frei wird, den nächsten offenen Exponenten.


    Mein Gedanke war, dass ganze nun auch mal auf unsere Uni-internen Hochleistungsrechner (sagt man das so? :D) laufen zu lassen.

    Ihr werdet jetzt sagen, dass python dafür die ganz falsche Wahl ist, das verstehe ich. In meiner Arbeit wird nunmal python benutzt und ich werde jetzt nicht extra dafür noch C++ lernen. Das ist aber auch nicht das wichtige, es sollen einfach Berechnungen und Statistiken angestellt werden, die über das handeslübliche Maß hinausgehen. Die Exponenten bis 50 zu untersuchen, ist mit einem Haushaltsrechner halt nicht möglich. Und auch 1000 verschiedene Werte h für den Exponenten k = 50.000 wird nicht mehr möglich sein.

  • Noch was: Wenn ich mir einen festen Exponenten nehme, beispielsweise k = 50.000, und ich möchte die Koeffizienten h von 1001 bis 2001 überprüfen. Dann kann ich doch auch das parallelisieren? Wie würde das aussehen?