Python – Die Collatz-Sequenz
On Dezember 1, 2020 by adminKann ich eine Überprüfung meines Codes für die Collatz-Sequenz aus Kapitel erhalten Drei von Automatisieren Sie die langweiligen Dinge mit Python ?
Die Collatz-Sequenz
Schreiben Sie eine Funktion namens collatz () mit einem Parameter namens number. Wenn die Zahl gerade ist, sollte collatz () die Zahl // 2 ausgeben und diesen Wert zurückgeben. Wenn die Zahl ungerade ist, sollte collatz () 3 * Nummer + 1 drucken und zurückgeben.
Schreiben Sie dann ein Programm, mit dem der Benutzer eine Ganzzahl eingeben kann und das bis zu diesem Zeitpunkt collatz () für diese Zahl aufruft Die Funktion gibt den Wert 1 zurück. (Erstaunlicherweise funktioniert diese Sequenz tatsächlich für jede Ganzzahl – früher oder später erhalten Sie mit dieser Sequenz 1! Selbst Mathematiker sind sich nicht sicher, warum. Ihr Programm untersucht die sogenannte Collatz-Sequenz , manchmal als „das einfachste unmögliche mathematische Problem“ bezeichnet.)
Denken Sie daran, den Rückgabewert von input () mit der Funktion int () in eine Ganzzahl umzuwandeln. Andernfalls handelt es sich um einen Zeichenfolgenwert.
Hinweis: Eine Ganzzahl ist gerade, wenn die Zahl% 2 == 0 ist, und es ist ungerade, wenn die Zahl% 2 == 1 ist.
Die Ausgabe dieses Programms könnte ungefähr so aussehen:
Enter number: 3 10 5 16 8 4 2 1
Eingabevalidierung
Fügen Sie dem vorherigen Projekt try- und exception-Anweisungen hinzu, um festzustellen, ob der Benutzer eine nicht ganzzahlige Zeichenfolge eingibt. Normalerweise löst die Funktion int () einen ValueError-Fehler aus, wenn eine nicht ganzzahlige Zeichenfolge wie in int („Puppy“) übergeben wird. Drucken Sie in der Ausnahmeklausel eine Nachricht an den Benutzer, dass er eine Ganzzahl eingeben muss.
Ich frage mich hauptsächlich, ob es eine sauberere Möglichkeit gibt, meine zu schreiben Lösung.
def collatz(num): while num > 1: if num % 2 == 0: print(num//2) num = num //2 elif num % 2 ==1: print(3*num+1) num = 3*num+1 else: print(num) def getNum(): global num num = (input("> ")) try: num = int(num) except ValueError: print("plese enter a number") getNum() getNum() collatz(num)
Kommentare
- Bitte fügen Sie eine Beschreibung hinzu, die angibt, was dieses Kapitel 3 mit Beispielen für Eingabe und Ausgabe empfiehlt. Niemand ‚ wird erraten, was das ist
- @Edmad Broctor und @ Carcigenicate Vielen Dank für Ihr Feedback. Ich habe meinen Beitrag überarbeitet.
- “ Erstaunlicherweise funktioniert diese Sequenz tatsächlich für jede Ganzzahl – früher oder später werden Sie mit dieser Sequenz ankommen bei 1! “ Eigentlich wissen wir ‚ nicht, dass es für jede ganze Zahl funktioniert, die Idee, dass es immer 1 erreichen wird, ist eine Vermutung .
- @PierreCath é Ich habe eine wirklich wunderbare Demonstration dieses Vorschlags, für den dieses Kommentarfeld zu klein ist.
- @Acccumulation Beeindruckend ! Das ‚ ist beeindruckend. In diesem Fall sollten Sie den Wikipedia-Artikel aktualisieren und sich an die International Mathematical Union wenden, um Ihre Fields-Medaille zu erhalten.
Antwort
Beachten Sie zunächst, wie Sie Berechnungen duplizieren:
print(num//2) num = num //2
Dies kann sein keine Probleme mit diesem spezifischen Code verursachen, aber es ist keine gute Praxis. Sie erledigen doppelt so viel Arbeit wie nötig, was zu Leistungsproblemen führen kann, sobald Sie anfangen, komplizierteren Code zu schreiben. Führen Sie die Berechnung einmal durch und speichern Sie das Ergebnis. In diesem Fall müssen Sie diese Zeilen jedoch nur umkehren und verwenden Sie num
:
num = num // 2 print(num)
Stellen Sie außerdem sicher, dass Sie den richtigen Abstand um Operatoren herum und konsistent sein .
Ihre if
und elif
Fälle schließen sich gegenseitig aus, und Ihre else
sollte niemals auftreten. Wenn die erste Bedingung wahr ist, müssen andere falsch sein und umgekehrt. Es besteht keine Notwendigkeit für die zweite Prüfung. Nach dem Umschreiben sehen Sie, dass das Drucken nicht in jedem Fall erforderlich ist. Sie können einfach nachher drucken:
while num > 1: if num % 2 == 0: num = num // 2 else: num = 3 * num + 1 print(num)
Da Sie nur num
eine von zwei Optionen basierend auf a erneut verwenden Bedingung, ein bedingter Ausdruck kann auch hier sauber verwendet werden:
while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) print(num)
Die geschweiften Klammern sind nicht erforderlich, aber ich denke, sie sind hier aufgrund der nützlich Anzahl der beteiligten Operatoren.
Das Drucken der Zahlen ist hier nicht ideal. In den meisten Codes müssen Sie in der Lage sein, die von Ihnen erzeugten Daten zu verwenden . Wenn Sie die produzierte Sequenz analysieren möchten, müssen Sie etwas tun, um die Standardausgabe abzufangen, was teuer und übermäßig kompliziert ist. Machen Sie es zu einer Funktion, die eine Liste akkumuliert und zurückgibt.In den folgenden Beispielen habe ich auch einige Typhinweise hinzugefügt, um den Datentyp klarer zu machen:
from typing import List def collatz(starting_num: int) -> List[int]: nums = [starting_num] num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) nums.append(num) return nums
Oder ein viel saubererer Ansatz besteht darin, ihn zu einem Generator zu machen, der die Zahlen liefert :
# Calling this function returns a generator that produces ints # Ignore the two Nones, as they aren"t needed for this kind of generator def collatz_gen(starting_num: int) -> Generator[int, None, None]: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield num >>> list(collatz_gen(5)) [5, 16, 8, 4, 2, 1]
Es gibt einige bemerkenswerte Dinge über getNum
:
Python verwendet „snake_case“ , nicht „camelCase“.
Ihre Verwendung von global num
ist hier unnötig und verwirrend Wie zuvor explizit return
alle Daten, die die Funktion erzeugt:
def get_num() -> int: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number") return get_num()
Beachten Sie, wie anstatt a neu zuzuweisen global num
geben wir nur die Nummer zurück. Ich habe auch ein bisschen Abstand gehalten und einige passendere Namen verwendet. Konzeptionell würde ich sagen, dass num = input("> ")
falsch ist. Zum Zeitpunkt der Ausführung ist num
nicht eine Zahl enthalten (es enthält eine Zeichenfolge).
Dies ist keine gute Verwendung der Rekursion. Es wird wahrscheinlich keine Probleme verursachen, aber wenn Ihr Benutzer wirklich dumm ist und ~ 1000 Mal falsche Daten eingibt, stürzt Ihr Programm ab. Verwenden Sie einfach eine Schleife:
def get_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
Verwenden Sie in Sprachen wie Python die Rekursion in Fällen, in denen Sie keine Garantie dafür haben, wie oft die Funktion wiederholt wird.
Ich würde auch Nennen Sie dies wahrscheinlich etwas näher an ask_for_num
. „get“ macht nicht sehr deutlich, woher die Daten kommen.
Insgesamt ergibt sich Folgendes:
from typing import Generator def collatz_gen(starting_num: int) -> Generator[int, None, None]: yield starting_num num = starting_num while num > 1: num = (num // 2) if num % 2 == 0 else (3 * num + 1) yield num def ask_for_num() -> int: while True: raw_num = input("> ") try: return int(raw_num) except ValueError: print("Please enter a number")
Dies kann wie folgt verwendet werden:
num = ask_for_num() for n in collatz_gen(num): print(n)
Antwort
Eingabeaufforderung
Die offensichtlichste schlechte Praxis hier ist die Verwendung einer globalen Variablen. Anstatt num
als Nebeneffekt festzulegen, sollte Ihre Funktion return
das Ergebnis sein.
getNum()
ist kein so guter Name für die Funktion. PEP 8 , der offizielle Styleguide für Python, sagt, dass Funktionsnamen lower_case_with_underscores
sein sollten. Darüber hinaus impliziert „get“, dass die Funktion ein Datenelement abruft, das bereits irgendwo gespeichert ist, was hier nicht der Fall ist. Schließlich sollte „Num“ spezifischer sein.
Die Verwendung der Rekursion ist nicht angemessen. Wenn Sie eine Schleife möchten, schreiben Sie eine Schleife.
def ask_integer(): """ Return an integer entered by the user (repeatedly prompting if the input is not a valid integer). """ while True: try: return int(input("> ")) except ValueError: print("Please enter an integer") num = ask_integer()
collatz
Funktion
Streng Sie haben die Anweisungen nicht befolgt. Ihre Lösung ist nicht falsch oder schlecht – Sie haben die Funktion collatz
gemäß der angegebenen Spezifikation, die dies besagt, einfach nicht implementiert Sie sollten eine einzelne Zahl drucken und zurückgeben.
def collatz(num): """ Given a number, print and return its successor in the Collatz sequence. """ next = num // 2 if num % 2 == 0 else 3 * num + 1 print(next) return next num = ask_integer() while num > 1: num = collatz(num)
Kommentare
- Kehren Sie den Test möglicherweise um und entfernen Sie ihn der Vergleich mit 0:
next = 3 * num + 1 if num % 2 else num // 2
- @RootTwo Ehrlich gesagt finde ich, dass dies die Absicht trübt. Wir ‚ sind Nicht prüfen, ob
num % 2
falsch ist; ‚ ist kein Prädikat. Wir ‚ sind Überprüfen, ob ‚ gleich 0 ist. Es kommt nur so vor, dass sie ‚ in Python äquivalent sind. -
next = ...
überschattet das integriertenext
. In diesem Zusammenhang ist ‚ wahrscheinlich nicht gefährlich, aber nur gut zu beachten - Technisch gesehen könnten Sie
if num % 2 else
, ich stimme zu, dass es wichtiger ist, hier die Absicht zu zeigen. undif num % 2 == 0 else
kommuniziert diese Absicht besser. Ich bin jedoch damit einverstanden, dass Sie Ihre Variablenext
umbenennen. ‚ ist eine schlechte Angewohnheit. - @ 200_success Vielen Dank, dass Sie darauf hingewiesen haben, dass ich die Nummer nicht zurückgegeben habe, sondern sie nicht einfach gedruckt habe. Das war sehr hilfreich.
Antwort
Der Vollständigkeit halber eine rekursive Implementierung für collatz
(Sie haben bereits genügend gute Vorschläge für die Eingabe von num
):
def collatz(num): print(num) if num == 1: return num if num % 2 == 0: return collatz(num // 2) return collatz(3 * num + 1) collatz(3)
Ausgaben
3 10 5 16 8 4 2 1
Kommentare
- Ich ‚ t Ich denke, diese Antwort hilft OP. Obwohl eine rekursive Definition sicherlich möglich ist, entspricht sie ‚ nicht der Spezifikation, die sie erfüllen möchten. Darüber hinaus weist dieser Code eine gewisse Redundanz auf: Die Funktion gibt immer 1 zurück (wenn überhaupt). Warum also überhaupt einen Rückgabewert?
- @MeesdeVries
the function always returns 1 (when it returns at all), so why even have a return value
Ich ‚ bin mir nicht sicher, ob ich folge. Die Rekursion muss einen Basisfall haben. Es ist einfach so, dass der Basisfall in diesem Beispielnum == 1
ist. Die Beispielausgabe zeigt, dass die Funktion nicht immer 1 zurückgibt. - Die Funktion gibt andere Werte aus, gibt jedoch nur den Wert 1 zurück.
- Ich bin nicht sicher, was Ihr Punkt ist . In meinem ursprünglichen Kommentar wurde darauf hingewiesen, dass die von Ihnen geschriebene Funktion nichts zurückgeben muss, da sie unabhängig von der Eingabe immer die Nummer 1 ist. Eine bessere Implementierung würde daher vermeiden, überhaupt einen Wert zurückzugeben, um den Vorschlag zu vermeiden, dass dies sinnvoll ist. Ich würde beispielsweise sagen, dass eine bessere Implementierung (des Rekursionsteils)
if num % 2 == 0: collatz(num//2); elif num > 1: collatz(3 * num + 1)
ist. - Ich lade Sie ein, den Code auszuprobieren, den ich selbst geschrieben habe, um dies zu sehen Dies ist nicht der Fall (zumindest für eine positive Ganzzahleingabe). Wenn Sie dies weiter diskutieren möchten, schlage ich vor, dass wir es zum Chatten nehmen.
Schreibe einen Kommentar