Kontrolle von zwei programmierten Aufgaben

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
Iftekher
User
Beiträge: 4
Registriert: Freitag 21. Dezember 2018, 17:24

Hallo Mitglieder,
ich habe zwei Aufgaben aus der Schule programmiert. Es funktioniert, allerdings will ich überprüfen lassen, ob es alle Bedingungen erfüllt.
Könnt Ihr diese zwei Aufgaben überprüfen und einer Rückmeldung geben.
Aufgabe 1

Code: Alles auswählen

print("Willkommen beim Programm Maxzahl, welches die größte Zahl in einer Liste und deren Position blitzschnell angibt!")
#Veränderung der Liste durch den Benutzer/Autor
liste=[ -4,6.5,2,-7,-4,-2,5,7,1.1,-3,-0.9,3,-5,6]

x=len(liste)              #Die Länge der Liste braucht man für das "range".
a=liste[0]                #Der Wert(Variable a) an der 1.Stelle von der Liste wird als Startwert genommen.
for i in range(1,x):
    b=liste[i]            #Die Zahlen ab 2.Zahl in der Liste(Variable b) in der Liste werden nacheinander mit Variable a verglichen.
    if a > b:
        a=a               #Falls Variable a größer als der Wert(Variable b) ist, dann bleibt a erhalten.
    else:
        a=b               #Sonst(Wenn b größer als a ist) wird Variable a durch die größere Zahl überschrieben.
        
print("Die größte Zahl in der Liste", liste, "ist", a, "." )




maxzahl=a                 #Der Wert, der zuvor durch die Schleife als größte Zahl definiert wurde, wird als Variable maxzahl definiert, um für Klarheit zu sorgen.
position=1                
for i in range(0,x):      #Die größte Zahl wird nochmal mit den nachfolgenden Zahlen in der Liste verglichen.
    if maxzahl == liste[i]:      
        print("Diese Zahl befindet sich an der" , position , ". Stelle der Liste.")  #Falls maxzahl ist gleich Zahl in der Liste, gibt das Programm die Position an.
    else:
        position=position + 1   #Sonst wird Variable position um 1 vergrößert. Somit wird bei jedem Durchgang die aktuelle Position geändert.



Aufgabe 2

Code: Alles auswählen

print("Willkommen beim Programm der Nullstellenberechnung, welche mithilfe des Intervallhalbierungsverfahren erfolgt.")
print()
print("Hierbei wird die Nullstelle von einer ganzrationalen Funktion vierten Grades innerhalb eines angegebenen Intervalls, die einen Vorzeichenwechsel vorweist,näherungsweise bestimmt.")
print()
print("Die Funktion heißt y=x**4 -9*x**3 + 24*x**2 - 20*x.") #Hier muss die veränderte Funktion ebenso aktualisiert werden.
print()
print("Geben Sie bitte das Intervall ein. Achten Sie dabei, dass der Abstand der beiden Intervallgrenzen nicht sonderlich groß sind. ")
print()
print("Bemerkung: Die linke Intervallgrenze ist immer kleiner als die rechte Intervallgrenze.")



def function(x):                                             #Veränderung der Funktion durch den Benutzer/Autor
    return 9*x**4 - 20*x


a=float(input("Bitte geben Sie die linke Intervallgrenze ein:"))           #Eingabe der linken und rechten Intervallgrenzen: 
b=float(input("Bitte geben Sie die rechte Intervallgrenze ein:"))          #Variable a und b definieren die linke und rechte Intervallgrenze
print()

while function(a)*function(b)>= 0:                                          #Überprüfung, ob die Funktionswerte zwei verschiedene Vorzeichen haben=Voraussetzung für Nullstelle
     print("Die angegebene Intervallgrenze ist nicht geeignet. Bitte geben Sie die Intervallgrenzen erneut ein.")
     a=float(input("Linke Intervallgrenze:"))                              #Wenn das Vorzeichen bei der Frage negativ ist, kann man davon ausgehen, dass einer der Funktionswerte negativ ist.
     b=float(input("Rechte Intervallgrenze:"))



print()
print("Ihr Intervall lautet:[",a,";",b,"]")
differenz=b-a                                                             #Variable für die Messung der Abstände zwischen der immer kleiner werdenden rechte und linke Intervallgrenze
intervallmitte=(a+b)/2                                                    #Intervallhalbierung
anzahl=0                                                                  #Anzahl der Intervallhalbierungsprozesse



if function(b)>=0:                                                        #Schleife und Abfrage, ob Nullstelle ein VZW von - nach + hat, oder umgekehrt.
    while differenz >= 0.001:            #Abweichung zwischen Intervallgrenze als Abfrage
        intervallmitte=(a+b)/2 
        anzahl=anzahl+1                   #Aktualisierung der Anzahl der Intervallhalbierungen bis Abweichung kleiner gleich 0.001 ist.
        if function(intervallmitte)>=0:    #Falls der Funktionswert von halbierten Intervall zugehörige x-Wert größer als 0 ist:
            b=intervallmitte              #neue Wertzuweisung von b
            differenz=b-a                 #Abweichung wird aktualisiert, aufgrund der neuen Wertzuweisungen
        else:
            a=intervallmitte              #Sonst(Wenn Funktionswert kleiner als 0, wird a einen neuen Wert zugewiesen, nämlich halbiert Intervall x-Wert ist a. 
            differenz=b-a


else:                                     #Nullstelle mit Vorzeichenwechsel von + nach -,weil Funktionswert bei b kleiner als 0 ist.
    while differenz >= 0.001:
        intervallmitte=(a+b)/2
        anzahl=anzahl+1
        if function(intervallmitte)>=0:   
            a=intervallmitte             #Einziger Unterschied: Wenn Funktionswert von Intervallhalbierten x-Wert größer als 0 ist, wird a einen neuen Wert zugewiesen.
            differenz=b-a
        else:
            b=intervallmitte
            differenz=b-a
         
print()
print("In den folgenden Zeilen erhalten Sie die Ergebnisse der Nullstellenuntersuchung:")
Nullstelle= ((a+b)/2)                         
print("Die Nullstelle befindet sich in dem angegebenen Intervall näherungsweise bei x=", Nullstelle)
print("Um diese Nullstelle näherungsweise zu bestimmen, hat das Programm das angegebene Intervall",anzahl, "mal halbiert.")
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

Befindet sich die größte Zahl mehrfach in der Liste, dann ist ab er zweiten Zahl die Position falsch. Warum zählst Du die Position nochmal extra, wenn Du doch schon i als Zählvariable hast? Statt über einen Index iteriert man direkt über die Liste und falls man noch einen Index braucht, nimmt man enumerate.
Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Iftekher: Zum ersten Programm:

Die Zeilen sind zu lang. Traditionell ist die Grenze bei 80 Zeichen. Der überarbeitete Style Guide for Python Code sieht das etwas entspannter, aber für meinen Geschmack gibt es noch zu viele Gelegenheiten bei denen Code der länger als 80 Zeichen pro Zeile ist, Probleme mit der Lesbarkeit verursacht. Kommentare werden, falls sie nicht sehr kurz sind, üblicherweise *vor* die Zeile(n) die sie kommentieren geschrieben.

Um Leerzeichen bei Zuweisungen (abgesehen von Schlüsselwortargumenten bei Funktionen/Methoden), sowie nach Kommas, stehen üblicherweise Leerzeichen, damit es besser lesbar ist.

`liste` ist kein guter Name, weil zu generisch. Der Listeninhalt hat hier zwar keine besondere Bedeutung, aber man könnte die Liste mindestens mal `zahlen` nennen, denn der Leser möchte in der Regel dringender wissen was eine Datenstruktur enthält, also was die Werte darin bedeuten, als das es sich um eine Liste handelt.

Statt nach der ersten Schleife dem Wert von `a` für das bessere Verständnis noch einen anderen Namen zu geben, sollte man gleich von Anfang an vernünftige Namen verwenden. Einbuchstabige Namen sind das recht selten. `x` und `b` sollten auch besser benannt werden. Zum Beispiel `anzahl` und `zahl`.

Das die Variablennamen so oft in den Kommentaren vorkommen ist nicht so gut, weil man dann auch die Kommentare grossflächig ändern und gegebenenfalls neu umbrechen muss, wenn man einen Variablennamen ändert. Die Kommentare sind sowieso grösstenteils überflüssig, weil die nur beschreiben was da schon als Code steht. Dafür sind Kommentare nicht da. Faustregel: Nicht kommentieren was der Code macht, sondern nur *warum* er das so macht. Sofern das nicht offensichtlich ist. Vor einem Kommentar sollte man immer überlegen ob man sich den sparen kann wenn man den Code verständlicher schreibt oder bessere Namen vergibt. Gerade bei Python kann man bei gut gewählten Namen Code schreiben, der sich fast flüssig vorlesen lässt.

Wenn ein Name aus mehr als einem Wort zusammengesetzt wird, sollten diese Worte durch einen Unterstrich getrennt werden.

Der ``if``-Zweig in der ersten Schleife macht keinen Sinn. Da sollte man die Bedingung umdrehen und nur den Zweig der tatsächlich etwas verändert im Code haben.

Die erste Schleife könnte dann so aussehen:

Code: Alles auswählen

    anzahl = len(zahlen)
    max_zahl = zahlen[0]
    for i in range(1, anzahl):
        zahl = zahlen[i]
        if zahl > max_zahl:
            max_zahl = zahl
Allerdings sind Indexzugriffe in Python, vor allem in Schleifen, ein „code smell“, weil man direkt über Elemente von Sequenzen iterieren kann, ohne den Umweg über einen Index. Im vorliegenden Fall könnte man zum Beispiel einfach über *alle* Zahlen iterieren, statt über alle ausser der ersten. Der eine unnötige Vergleich am Anfang fällt kaum ins Gewicht, der Code wird aber deutlich einfacher – ⅓ kürzer und man spart zwei Variablen:

Code: Alles auswählen

    max_zahl = zahlen[0]
    for zahl in zahlen:
        if zahl > max_zahl:
            max_zahl = zahl
Letztlich geht das aber auch sehr kurz in einer einzigen Zeile, denn es gibt die `max()`-Funktion:

Code: Alles auswählen

    max_zahl = max(zahlen)
Beim Ausgeben der grössten Zahl ist ein Leerzeichen zwischen der Zahl und dem Punkt/Satzzeichen. An der Stelle würde man eher die `format()`-Methode auf Zeichenketten, oder f-Zeichenketten verwenden. Das gleiche Problem mit einem Leerzeichen gibt es auch bei der Ausgabe der Position(en).

In der zweiten Schleife wird `position` falsch berechnet. Das stimmt nur für den ersten Treffer. Wenn der Maximalwert mehrfach in der Liste vorkommt, werden falsche Positionen ausgegeben.

Allerdings ist `position` auch überflüssig, denn der korrekte Wert ist immer um eins grösser als `i`. Also kann man auch einfach ``i + 1`` als Position ausgeben und die Variable `position` ganz weglassen. Oder aber `position` beibehalten und über `enumerate()` erzeugen, und dafür dann `i` weglassen.

Dann sähe das Programm so aus:

Code: Alles auswählen

#!/usr/bin/env python3


def main():
    print(
        'Willkommen beim Programm Maxzahl, welches die größte Zahl in einer'
        ' Liste und deren Position blitzschnell angibt!'
    )
    # 
    # Veränderung der Liste durch den Benutzer/Autor.
    # 
    zahlen = [-4, 6.5, 2, -7, -4, -2, 5, 7, 1.1, -3, -0.9, 3, -5, 6]

    max_zahl = max(zahlen)
    print(f'Die größte Zahl in der Liste {zahlen} ist {max_zahl}.')

    for position, zahl in enumerate(zahlen, 1):
        if max_zahl == zahl:      
            print(
                f'Diese Zahl befindet sich an der {position}. Stelle der Liste.'
            )


if __name__ == '__main__':
    main()
Falls nur der erste Treffer ausgegeben werden sollte, dann kann man sich auch die zweite Schleife sparen und einfach ``position = zahlen.index(max_zahl)`` schreiben.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei Aufgabe 2 wird die erste Zuweisung von intervallmitte nicht gebraucht. Die beiden while-Schleifen sind fast identisch und können durch eine kleine Umstellung sogar zusammengefasst werden. Statt differenz an vielen Stellen zu berechnen wäre es einfacher b-a direkt als Bedingung zu nehmen. Auch hier beschreiben die meisten Kommentare nur das, was sowieso schon im Code steht.
Iftekher
User
Beiträge: 4
Registriert: Freitag 21. Dezember 2018, 17:24

Vielen Dank Mitglieder,
die Kommentare haben mir geholfen. Allerdings möchte ich Euch mitteilen, dass bei der ersten Aufgabe, die Funktion index und max verboten waren, bzw.
nicht verwendet werden dürfen. Außerdem ist es vorgesehen, dass die größte Zahl einmal in der Liste vorkommt.
Bei Aufgabe 2 ist bei dem Vorgang der Intervallhalbierungsverfahren nur die Nullstellen (von - nach +) und (von + nach -) vorgesehen.
Mein Programm habe ich entsprechend geändert.
Danke an Allen!!
Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Iftekher: Wenn der grösste Wert nur einmal vorkommt, beziehungsweise nur das erste Vorkommen zu einer Ausgabe führen soll, dann kannst Du die Schleife ja abbrechen nach der Ausgabe. Sonst läuft die unnötig durch die Elemente nach dem (ersten) grössten Wert.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Iftekher
User
Beiträge: 4
Registriert: Freitag 21. Dezember 2018, 17:24

Hallo Blackjack,
hier hast Du ein deutlich verkürztes Code.
Schau es Dir bitte an und probiere es an verschiedenen Listen und beachte dabei, dass eine Zahl in der Liste nicht wiederholt wird.
Könntest du auf folgende Punkte bei Deiner Untersuchung achten?
1. läuft ohne Fehlermeldung
2.erzeugt die korrekte Ausgabe(Maximum und Position)
3. Lesbarkeit des Codes (aussagekräftige Variablen, Kommentar)

Code: Alles auswählen

print("Willkommen beim Programm Maxzahl, welches die größte Zahl in einer Liste und deren Position blitzschnell angibt!")

#Veränderung der Zahlenliste durch den Benutzer/Autor
zahlenliste = [ 4,6,2,-7,-4,-2,0,7.01,7,1,-3,-1,3,7.011,-5,-6]


anzahl = len(zahlenliste)              
zahl = zahlenliste[0]             #Der Wert an der 1.Stelle wird als Startwert genommen, um für den Vergleich mit den anderen Zahlen zu dienen.


for i in range(1,anzahl):
    zahl_i = zahlenliste[i]       #werden nacheinander mit dem Startwert verglichen,um zu überprüfen, ob es noch eine größere Zahl gibt.
    if zahl < zahl_i :
        zahl = zahl_i                             
        position = i+1          #Die Position wird dann aktualisiert, wenn der Startwert einen neuen Wert zugewiesen wird.
        

print("Die größte Zahl in der Liste", zahlenliste, "ist", zahl, "." )
print("Diese Zahl befindet sich an der" , position , ". Stelle der Liste.") 
Sirius3
User
Beiträge: 18268
Registriert: Sonntag 21. Oktober 2012, 17:20

Es ist immer noch so, dass man nicht über einen Index iterieren sollte, sondern über die Elemente der Liste direkt, wenn man zusätzlich einen Index braucht, nimmt man enumerate. Aber das hat __blackjack__ ja schon alles inklusive Beispielcode geschrieben. Das zu ignorieren und dann nach Lesbarkeit zu fragen, ist schon frech.
`position` ist möglicherweise nicht definiert und führt zu einem NameError. Die Kommentare in Bezug zum Startwert sind (bis auf den ersten) falsch, was enthält die Variable `zahl` denn wirklich? Und hier kommen wir dann zu den schlechten Namen, weil sie alle nicht zu ihrer Bedeutung im Code passen. Auch hier hat __blackjack__ schon bessere in seinen Beispielen verwendet.
Iftekher
User
Beiträge: 4
Registriert: Freitag 21. Dezember 2018, 17:24

Hallo Sirius,
mir Frechheit vorzuwerfen, ist eine Voreingenommenheit. Ich habe es sowohl den Beitrag von Blackjack geschaut.
Du hättest die drauffolgende Antwort lesen sollen, bevor Du mich beantwortest.
Ich habe einen Grund, warum ich bestimmte Funktionen von python vermeide.
Außerdem soll die Unterschrift des Autors erkannbar sein, sodass kein Plagiat vorgeworfen werden kann, weil der Prüfer mein Programmstill weiß.
Und noch zu den Variablennamen: Ich habe die schon größtenteils übernommen.
Danke
Benutzeravatar
__blackjack__
User
Beiträge: 14036
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Iftekher: Ich habe ja nicht nur `max()` und die `index()`-Methode sondern auch die Zwischenschritte dort hin in meinem Beitrag beschrieben, und teilweise auch als Code gezeigt.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten