Erstellen einer Polynomklasse / Methode f. Ableitung

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
Mitch_92
User
Beiträge: 3
Registriert: Freitag 10. Juli 2020, 12:35

Hallo zusammen,

für die Uni steht bei mir diesen Semester eine Einführung in Python an. Aufgrund der Corona-Situation ist allerdings der komplette Kurs in Eigenregie online zu erledigen. Das klappt soweit auch ganz gut mit den bereitgestellten Unterlagen, allerdings hänge ich jetzt seit Stunden an einer Aufgabe und befürchte, ich sehe den Wald vor lauter Bäumen einfach nicht. Nachfragen beim Dozenten sind auch schwierig, deswegen hoffe ich darauf, dass ihr mir vielleicht auf den Sprung helfen mögt, denn im Internet habe ich auch nichts gefunden, was mir weiterhilft.

Es geht darum, eine Klasse zu schreiben, die ein Polynom beschreibt. Zusätzlich soll es Methoden geben, die dieses Polynom an einer Stelle x auswerten und eine weitere, die die Ableitung bildet. Die Ableitung soll dabei ebenfalls wieder ein Polynom sein. Die Auswertung an Stelle x funktioniert. Problematisch ist die Ableitung, also die untere Methode. Offenbar funktioniert die Funktion an sich schon (zumindest gibt sie die richtigen Koeffizienten aus). Wenn ich allerdings dann versuche, die erhaltene Ableitung an einer Stelle x auszuwerten (müsste ja gehen, wenn sie ebenfalls ein Polynom ist), bekomme ich folgenden Fehler: "can't multiply sequence by non-int of type 'float'"
Daran verzweifle ich seit Stunden. Hat jemand einen Tipp für mich?

class Polynom:
"""Erstellen der Polynome mit Koeffizienten koeff, Eingabe in der Form ko_1*x**n, ko_2*x**(n-1), ..."""

def __init__(self, *koeff):
"""Speichern der eingegebenen Parameter als Liste"""
self.koeff = list(koeff)

def eval(self, x):
"""Auswertung des Polynoms an der Stelle x, Rueckgabewert y"""
y = 0
for i in range(len(self.koeff)):
y+=(self.koeff*x**(len(self.koeff)-i-1))
return(y)

def derivative(self):
"""Bilden einer Ableitung"""
diff = []
for i in range(len(self.koeff)-1):
diff.append((len(self.koeff)-(i+1))*self.koeff)
print(diff)
deriv = Polynom(diff)
return(deriv)
Freumel
User
Beiträge: 69
Registriert: Donnerstag 25. Januar 2018, 13:47

Code: Alles auswählen

y = 0
for i in range(len(self.koeff)):
    y+=(self.koeff*x**(len(self.koeff)-i-1))
self.koeff ist eine Liste. In dem Sinne würde ich deine Eingabe korrigieren:

Code: Alles auswählen

y = 0
for i in range(len(self.koeff)):
     y+=(self.koeff[i]*x**(len(self.koeff)-i-1))
Wobei das noch etwas cooler gehen würde:

Code: Alles auswählen

y = 0
for i,koeff in enumerate(self.koeff):
     y+=(koeff*x**(len(self.koeff)-i-1))
Wichtig bei dem unteren Beispiel: koeff != self.koeff
Das ist ein "For Each" Loop über eine Liste. Gucke dir dazu gerne mal etwas an.
Ansonsten macht es natürlich Sinn den Grad der Funktion als Variable auszudrücken und den Code wie folgt zu formulieren:

Code: Alles auswählen

y = 0
deg = len(self.koeff)
for i,koeff in enumerate(self.koeff):
     y+=(koeff*x**(deg-i-1))

Und wenn du richtig gut bist, gucke dir gerne mal die List Komprehentions in Python an:

Code: Alles auswählen

y = 0
deg = len(self.koeff)
value_list = [koeff*x**(deg-i-1) for i,x in self.koeff]
for value in value_list:
    y += value
Wobei das noch ne Spur cooler geht:

Code: Alles auswählen

 
deg = len(self.koeff)
y = sum([koeff*x**(deg-i-1) for i,x in self.koeff])
Benutzeravatar
__blackjack__
User
Beiträge: 14012
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mitch_92: Zu einer Fehlerbeschreibung gehört auch der Code der den behaupteten Fehler auslöst. Ich bekomme den nämlich nicht. Dafür einen anderen.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Sirius3
User
Beiträge: 18255
Registriert: Sonntag 21. Oktober 2012, 17:20

@Freumel: der Index war schon richtig, nur das [ i ] wird ohne Code-Tags als Kursiv interpretiert.

Richtig Cool ist es, Polynome mit Hilfe des Horner-Schemas zu berechnen, dazu werden die Koeffizienten ja schon in der richtigen Reihenfolge übergeben, nämlich beginnend mit dem der größten Potenz. Bitte benutze keine Abkürzungen, wenn Du Koeffizienten meinst, dann schreib die auch aus, oder besser gleich auf Englisch, da ja alles andere auch englisch ist.
`return` ist keine Funktion, also gehören da auch keine unnötigen Klammern hin.

Code: Alles auswählen

class Polynom:
    """Erstellen der Polynome mit Koeffizienten koeff, Eingabe in der Form ko_1*x**n, ko_2*x**(n-1), ..."""
    
    def __init__(self, *coefficients):
        """Speichern der eingegebenen Parameter als Liste"""
        self.coefficients = coefficients
        
    def eval(self, x):
        """Auswertung des Polynoms an der Stelle x, Rueckgabewert y"""
        y = 0
        for coefficient in coefficients
            y = y * x + coefficient
        return y

    __call__ == eval

    def derivative(self):
        """Bilden einer Ableitung"""
        new_coefficients = []
        for power, coefficient in reversed(enumerate(reversed(self.coefficients[:-1]), 1)):
            new_coefficients .append(power * coefficient)
        return Polynom(new_coefficients)
Bei solchen Klassen wird oft __call__ überschrieben, dann verhält sich eine Instanz wie eine Funktion und kann aufgerufen werden.

@Mitch_92: hast Du mal das was Du bei Polynom als Argumente übergibst mit dem verglichen, was beim Erzeugen innerhalb von `derivate` verwendet wird? Einfach mal in __init__ coefficients per print ausgeben und schauen, was der Unterschied ist.
Benutzeravatar
__blackjack__
User
Beiträge: 14012
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mitch_92: Anmerkungen zum Code: Mit beliebigen Positionsargumenten sollte man sparsam umgehen. Statt die Koeffizienten als einzelne Argumente an die `Polynom.__init__()` zu übergeben sollte man da schon eine Liste (oder generell etwas iterierbares) als *ein* Argument übergeben. Genau dieser magische Kram ist nämlich Dein Problem, denn da brauchst Du dann auch beim Aufruf die Magie.

Namen sollten nicht kryptisch abgekürzt werden. Wenn man `koeffizienten` meint, sollte man nicht nur `koeff` schreiben. Und man sollte sich für Deutsch oder Englisch entscheiden und kein Denglisch.

Das die eingegebenen Parameter als Liste gespeichert werden ist ein Implementierugsdetail, das hat nichts im Docstring zu suchen. Ebensowenig das beim Auswerten der lokale Name `y` lautet.

``for i in range(len(sequence)):`` ist ein „anti pattern“ in Python. Man kann in Python *direkt* über die Elemente von Sequenztypen wie Listen iterieren. Falls man *zusätzlich* einen laufenden Wert braucht, gibt es die `enumerate()`-Funktion.

In diesem Falle wäre `exponent` auch ein passendere Name für `i`.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3


class Polynom:
    """
    Erstellen der Polynome mit Koeffizienten coefficients, in der Form
    ko_1*x**n, ko_2*x**(n-1), ...
    """

    def __init__(self, coefficients):
        self.coefficients = list(coefficients)

    def __repr__(self):
        return f"{self.__class__.__name__}({self.coefficients!r})"

    def __call__(self, x):
        """
        Wertet Polynom an Stelle `x` aus.
        """
        return sum(
            coefficient * x ** exponent
            for exponent, coefficient in enumerate(reversed(self.coefficients))
        )

    def derivative(self):
        """
        Bildet die Ableitung.
        """
        return Polynom(
            [
                coefficient * exponent
                for coefficient, exponent in zip(
                    self.coefficients[:-1],
                    reversed(range(len(self.coefficients))),
                )
            ]
        )


def main():
    polynom = Polynom([5, 8, 7, 5, 3, 9])
    print(polynom)
    print(polynom.derivative())
    print(polynom(23))
    print(polynom.derivative()(42))


if __name__ == "__main__":
    main()
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Mitch_92
User
Beiträge: 3
Registriert: Freitag 10. Juli 2020, 12:35

Wow, das ging ja mal schnell!
Mein Ursprungsproblem scheint wohl tatsächlich eher am Aufruf zu liegen, denn meine oben vorgestellte Lösung wurde vom Dozenten inzwischen als richtig bewertet...
Dennoch werde ich natürlich mal schauen, dass ich das ganze mit Hilfe eurer Antworten noch besser und schöner gestalten kann.
Danke euch vielmals, für mich als absoluten Anfänger (nicht nur in Python, sondern allgemein im Programmieren) ist sowas echt Gold wert =)
Antworten