Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 791 – math.integer — Untermodul für mathematische Funktionen, die auf Ganzzahlen spezialisiert sind

Autor:
Sergey B Kirpichev <skirpichev at gmail.com>
Sponsor:
Victor Stinner <vstinner at python.org>
Discussions-To:
Discourse thread
Status:
Entwurf
Typ:
Standards Track
Erstellt:
12. Mai 2025
Python-Version:
3.15
Post-History:
12. Jul. 2018, 09. Mai 2025, 19. Mai 2025

Inhaltsverzeichnis

Zusammenfassung

Dieses PEP schlägt ein neues Untermodul für zahlentheoretische, kombinatorische und andere Funktionen vor, die für ganzzahlige Argumente definiert sind, wie z.B. math.gcd() oder math.isqrt().

Motivation

Die Dokumentation von math besagt: „Dieses Modul bietet Zugriff auf die vom C-Standard definierten mathematischen Funktionen.“ Im Laufe der Zeit wurde das Modul jedoch mit Funktionen befüllt, die nicht mit dem C-Standard oder der Gleitkomma-Arithmetik zusammenhängen. Jetzt ist es wesentlich schwieriger, den Geltungsbereich, den Inhalt und die Schnittstellen (zurückgegebene Werte oder akzeptierte Argumente) des Moduls zu beschreiben.

Zum Beispiel die folgende Aussage aus der Dokumentation: „Sofern nicht anders angegeben, sind alle Rückgabewerte Floats.“ Dies trifft nicht mehr zu: *Keine* der Funktionen, die im Unterabschnitt Zahlentheoretische Funktionen der Dokumentation aufgeführt sind, gibt einen Float zurück, aber die Dokumentation sagt dies nicht. In der Dokumentation für das vorgeschlagene Untermodul math.integer wäre der Satz „Alle Rückgabewerte sind Integer“ zutreffend. Auf ähnliche Weise können wir die Beschreibung der akzeptierten Argumente für Funktionen sowohl im neuen Untermodul als auch in math vereinfachen.

Jetzt ist es viel schwieriger, die Erwartungen der Leute an den Modulinhalt zu erfüllen. Sollen sie beispielsweise erwarten, dass math.factorial(100) eine exakte Antwort liefert? Viele Sprachen, Python-Pakete (wie scipy) oder Taschenrechner haben Funktionen mit gleichem oder ähnlichem Namen, die einen Gleitkommawert zurückgeben, der in diesem Beispiel nur eine Annäherung ist.

Offensichtlich kann das Modul math nicht als Sammelstelle für mathematische Funktionen dienen, da wir auch die Module cmath und statistics haben. Machen wir dasselbe für Integer-bezogene Funktionen. Dies schafft einen gemeinsamen Kontext, der die Ausführlichkeit der Dokumentation und die konzeptionelle Belastung reduziert. Es fördert auch die Auffindbarkeit durch Gruppierung verwandter Funktionen und macht IDE-Vorschläge (z.B. die neue REPL von CPython) hilfreicher.

Derzeit umfasst der Code des Moduls math in CPython etwa 4200 Zeilen Code, wovon der Code des neuen Moduls etwa 1/3 (1300 Zeilen) ausmacht. Dies ist vergleichbar mit cmath (1340 Zeilen), das *kein* einfacher Wrapper für libm ist, so wie die meisten Funktionen im Modul math.

Und diese Situation verschlimmert sich tendenziell. Als die Aufteilung des Moduls erstmals vorgeschlagen wurde, gab es nur zwei Integer-bezogene Funktionen: factorial() (akzeptierte auch floats, wie andere Funktionen im Modul) und gcd() (verschoben aus dem Modul fractions). Dann wurden isqrt(), comb() und perm() hinzugefügt, und die Einführung des neuen Moduls wurde zweimal vorgeschlagen, so dass alle neuen Funktionen direkt dorthin gehen würden, ohne den Namensraum von math zu belasten. Jetzt gibt es sechs Funktionen, und factorial() akzeptiert keine floats mehr.

Einige mögliche Ergänzungen, unter denen, die in der ursprünglichen Diskussionsrunde und in Issue python/cpython#81313 vorgeschlagen wurden, sind:

  • c_div() und n_div() – für Ganzzahldivision mit Rundung zur positiven Unendlichkeit (Decken-Division) und zur nächsten Ganzzahl, siehe relevanter Diskussionsfaden. Dies wurde mehrmals in der Standardbibliothek neu erfunden, z.B. in datetime und fractions. Und es ist leicht, dies falsch zu machen, wie der Thread zeigt.
  • gcdext() – zum Lösen linearer Diophantischer Gleichungen in zwei Variablen (die int-Implementierung beinhaltet tatsächlich einen erweiterten Euklidischen Algorithmus)
  • isqrt_rem() – um sowohl eine ganzzahlige Quadratwurzel als auch einen Rest zurückzugeben (der nur dann ungleich Null ist, wenn die Ganzzahl keine perfekte Quadratzahl ist)
  • ilog() – Integer-Logarithmus, math.log() hat spezielle Behandlung für ganzzahlige Argumente. Sie ist einzigartig (im Vergleich zu anderen Modulfunktionen) und bisher nicht dokumentiert, siehe Issue python/cpython#120950.
  • fibonacci()Fibonacci-Folge.

Ein getrennter Namensraum eliminiert mögliche Namenskonflikte mit vorhandenen Funktionen des Moduls math. Zum Beispiel werden mögliche Namen wie ceil_div() oder ceildiv() für die ganzzahlige Decken-Division mit ceil() kollidieren (die für floats ist und *manchmal* für ganzzahlige Division das Richtige tut, als Zufall – aber normalerweise nicht).

Begründung

Geht es hier nur um Dokumentation, warum wird diese nicht stattdessen korrigiert? Nein, das ist nicht der Fall. Sicherlich können wir im Präambel des Moduls viel vager sein (d.h. ungefähr sagen, dass „das Modul math einige mathematische Funktionen enthält“), wir können die Eingabe/Ausgabe für jede Funktion und ihr Verhalten genau beschreiben (z.B. ob die Ausgabe von factorial() exakt ist oder nicht, wie bei scipy.special.factorial, standardmäßig).

Das Hauptproblem ist jedoch, dass das aktuelle Modul unterschiedliche, fast nicht zusammenhängende Anwendungsbereiche vermischt. Das Hinzufügen weiterer Dokumentation wird dies nur hervorheben und das Problem für Endbenutzer verschlimmern (mehr Text zum Lesen/Überspringen). Und es wird das Problem der Auffindbarkeit (um zu wissen, in welchem Modul eine Funktion zu finden ist und dass sie überhaupt gefunden werden kann, muss man alle Funktionen im Modul betrachten) und auch des Tab-Abschlusses nicht lösen.

Spezifikation

Das PEP schlägt vor, die folgenden Integer-bezogenen Funktionen in ein neues Untermodul namens math.integer zu verschieben:

Ihre Aliase in math werden sanft veraltet sein. Dieses PEP führt keine rückwärtsinkompatiblen Änderungen ein.

Modulfunktionen akzeptieren Integer und Objekte, die die Methode __index__() implementieren, die verwendet wird, um das Objekt in eine ganze Zahl umzuwandeln. Geeignete Funktionen müssen exakt berechnet werden, sofern genügend Zeit und Speicher vorhanden sind.

Das Paket intmath wird für ältere Python-Versionen neuen Inhalt für das Untermodul bereitstellen.

Mögliche Erweiterungen

Neue Funktionen (wie im Abschnitt Motivation erwähnt) sind nicht Teil dieses Vorschlags.

Wir sollten jedoch erwähnen, dass, sofern wir nicht einfach Bindungen zu einer gut unterstützten mathematischen Bibliothek wie GMP bereitstellen können, der Umfang des Untermoduls begrenzt sein sollte. Zum Beispiel keine Primzahltests und Faktorisierungen, da produktionsreife Implementierungen einen soliden mathematischen Hintergrund von Mitwirkenden erfordern und eher spezialisierten Bibliotheken angehören.

Wenn eine vorgeschlagene Funktion bereits in gmpy2 vorhanden ist, sollten wir eine kompatible Schnittstelle für die Standardbibliothek bevorzugen.

Abwärtskompatibilität

Da Aliase in math auf unbestimmte Zeit beibehalten werden (deren Verwendung würde entmutigt), werden keine Codebrüche erwartet.

Wie man das lehrt

Das neue Untermodul wird ein Ort für Funktionen sein, die 1) Integer-ähnliche Argumente akzeptieren und auch Integer zurückgeben, und 2) auch im Bereich der beliebigen Präzisions-Ganzzahlarithmetik liegen, d.h. keine Abhängigkeit von der plattformabhängigen Gleitkommaformatierung oder -verhalten und/oder von der plattformabhängigen Mathematikbibliothek (libm) haben.

Für Benutzer wäre es natürlich, zuerst nach den Methoden von int zu suchen, die die meisten grundlegenden Anwendungsfälle abdecken (z.B. die Methode int.bit_length()), als zu einem dedizierten Ort in der Standardbibliothek.

Referenzimplementierung

python/cpython#133909

Abgelehnte Ideen

Umbenennung von isqrt()

Es gab eine kurze Diskussion darüber, math.isqrt() als imath.sqrt verfügbar zu machen, so wie cmath.sqrt() die komplexe Version von math.sqrt() ist. Allerdings ist isqrt letztendlich eine andere Funktion: es ist der Boden der Quadratwurzel. Es wäre verwirrend, ihr denselben Namen (unter einem anderen Modul) zu geben.

Modulname

Eine Umfrage zeigte intmath als beliebtesten Kandidaten mit imath als zweitplatzierten.

Weitere vorgeschlagene Namen sind ntheory (wie das Untermodul von SymPy), integermath, zmath, dmath und imaths.

Aber das SC bevorzugt ein Untermodul anstelle eines neuen Top-Level-Moduls. Die beliebtesten Varianten des Untermoduls von math sind: integer, discrete oder ntheory (Autorenpräferenz).

Danksagungen

Danke an Tim Peters für die Wiederbelebung der Idee, das Modul math aufzuteilen. Danke an Neil Girdhar für substanzielle Verbesserungen des ursprünglichen Entwurfs.


Quelle: https://github.com/python/peps/blob/main/peps/pep-0791.rst

Zuletzt geändert: 2025-10-14 09:50:08 GMT