Seite 1 von 1

python problem

Verfasst: Dienstag 16. November 2004, 21:55
von Kranioklast
Ich habe mal wieder ein Problem:
Die Aufgabe lautet:
Schreiben Sie eine Prozedur wie folgt:

def etwa_gleich(testwinkel, winkel, plusminus):
"""\
Voraussetzung: "testwinkel" und "winkel" sind ahlen im
Bereich zwischen 0.0 und < 360.0, plusminus im
Bereich zwischen 0.0 und < 180.0 (Altgradwinkel).
Effekt: Der Winkel, der um "plusminus" vor "winkel" liegt,
und der, der um "plusminus" nach "winkel" liegt,
bilden einen Bereich. Wenn der Wert von
"testwinkel" innerhalb dieses Bereiches liegt
(Grenzen eingeschlossen), ist True geliefert, sonst
False.
"""

Bisher hab ich das:

Code: Alles auswählen

def etwa_gleich(testwinkel, winkel, plusminus):
    testwinkel>=0<360
    winkel>=0<360
    plusminus>=0<180
    bereich1=winkel-plusminus
    bereich2=winkel+plusminus
    if testwinkel <= bereich1:
        return testwinkel
    if testwinkel <= bereich2:
        return testwinkel
etwa_gleich(120,100,10)
Ich glaube, das ist quatsch, aber wie geht es besser?

Danke für Tipps!

Verfasst: Dienstag 16. November 2004, 22:33
von jens
Generell solltest du mehr IFs benutzen, denn sowas wie testwinkel>=0<360 bringt nichts ;)
Dann sollte eine IF-Abfrage entweder mit "return True" oder "return False" enden...

Verfasst: Dienstag 16. November 2004, 22:39
von Dookie
Hi Kranikolast,

geht auch ohne if ;)

Code: Alles auswählen

def etwagleich(a, b, plusminus=1.0):
    return min((a-b)%360.0, (b-a)%360.0) <= plusminus

Gruß

Dookie

Verfasst: Dienstag 16. November 2004, 23:03
von Kranioklast
Vielen Dank!! Wenn ich stecken bleibe, melde ich mich wieder. :D

Verfasst: Mittwoch 17. November 2004, 14:33
von Kranioklast
Was genau bewirkt denn das %?
Damit habe ich bisher noch nicht gearbeitet.

Danke!!

Verfasst: Mittwoch 17. November 2004, 14:45
von mawe
Hi!

% ist der Modulo-Operator (heisst der überhaupt so?). Banal gesagt liefert modulo den Rest einer Division:

Code: Alles auswählen

>>> 4%3   # 4/3 = 1, Rest = 1
1
>>> 14%4  # 14/4 = 3, Rest = 2
2
>>> 12%3  # 12/3 = 4, Rest = 0
0
Gruß, mawe

Verfasst: Mittwoch 17. November 2004, 14:52
von Dookie
Hi nochmal,

hab beim austüfteln des oben geposteten Codes herausgefunden, daß der Modulo % auch mit Fließkommazahlen funktioniert, divmod geht auch.

Code: Alles auswählen

>>> import math
>>> print 10.0 % math.pi
0.575222039231

>>> print divmod(10.0, math.pi)
(3.0, 0.57522203923062065)
Gruß

Dookie

Verfasst: Mittwoch 17. November 2004, 19:56
von Kranioklast
Vielen Dank für die Hilfe.
Ich verstehe allerdings nicht genau, was sich dort
abspielt und habe mit den mir zur Verfügung stehenden
Mitteln auch eine Lösung gefunden.
Nur wie kann ich überprüfen, ob es funktiniert?
Meine Lösung:

Code: Alles auswählen

def etwa_gleich(testwinkel, winkel, plusminus):
    bereich1=winkel-plusminus
    bereich2=winkel+plusminus
    if testwinkel >= bereich1 and testwinkel <= bereich2:
        return True
    else:
        return False

Verfasst: Mittwoch 17. November 2004, 21:20
von Christopy
Manchmal hab ich das Gefühl, dass Dookie hauptberuflich als Obfuscator arbeitet ;) :D :prost:

Finde Deine Lösung viel übersichtlicher, Kranioklast. Teste einfach ein paar Fälle (vor allem Grenzfälle) per Hand nach. (Ausgaben mit print helfen dabei...) Für ausgetüftelte Tests wird der gewiefte Pythonier zu Unit Tests greifen. Hab ich aber auch noch nie was mit gemacht... :(

Verfasst: Mittwoch 17. November 2004, 21:40
von jens
Finde ehrlich gesagt, die Lösung von Kranioklast auch lesbarer, als Dookie's kompressions-Version :lol:

Wenn es dir hilft, dann kannst du evtl auch per Schleifen deine Funktion überprüfen, in etwa so:

Code: Alles auswählen

for i in xrange(0,10):
    print i,":", etwa_gleich(i, 5, 1)
Ergebnis:

Code: Alles auswählen

0 : False
1 : False
2 : False
3 : False
4 : True
5 : True
6 : True
7 : False
8 : False
9 : False
Wobei mir da eine Zwischenfrage an die Allgemeinheit einfällt: Warum kann man mit range() keine anderen Schrittwerte als Ganzzahlen verwenden??? Also sowas wie:

Code: Alles auswählen

range(0,10,0.1)

Verfasst: Mittwoch 17. November 2004, 21:41
von fs111
Christopy hat geschrieben:Manchmal hab ich das Gefühl, dass Dookie hauptberuflich als Obfuscator arbeitet ;) :D :prost:
Dookie leidet unter akuter alles-in-einer-Zeile-Macheritis ;)

fs111

Verfasst: Mittwoch 17. November 2004, 21:53
von Milan
HI. Wo ist das Problem? Leide ich doch auch drunter :wink: Aber bitte, wenn schon, denn schon! (hmm, Test auf zwischen 0 bis 360 fehlt, den hat Dookie mit drin... aber min ließt sich net so schön wie Betrag finde ich :wink: )

Code: Alles auswählen

def etwa_gleich(tw,w,pm):
    return abs(w-tw)<=pm

Verfasst: Mittwoch 17. November 2004, 22:23
von Dookie
Hi Kranioklast,

deine Lösung wird Probleme haben, falls winkel nah bei 0° oder 360° liegt und die berechnung mit plusminus 360° über- bzw. 0° unterschreitet.

Code: Alles auswählen

>>> print etwa_gleich(5, 359, 10)
False
Passt nicht da 359°+10° = 369° ist was 9° entspricht. Das könntest Du jetzt mit einer ganzen Reihe von IFs testen und für jeden Sonderfall eine Sonderbehandlung programmieren oder halt eine besser Möglichkeit suchen.
Du kannst z.B. den Winkel zwischen a und b leicht ausrechnen indem du b von a abziehst (vorausgesetzt b < a sonst a von b abziehen) und die Differenz mit plusminus vergleichst.

Code: Alles auswählen

def etwa_gleich(testwinkel, winkel, plusminus):
    if testwinkel >= winkel:
        abstand = testwinkel-winkel
    else:
        abstand = winkel-testwinkel
    return abstand <= plusminus
so das löst aber noch nicht obiges Problem wenn der Bereich zwischen testwinkel und winkel die 0° bzw 360° überschneidet.
Hier hilft uns der Modulo, der dafür sorgen kann, daß der Bereich immer zwischen 0 und 360° bleibt. Da Irgendeinwinklel % 360 immer im Bereich 0 - 359 ist.
Schauen wir uns nochmal ein Beispiel an:

Code: Alles auswählen

   /
__/
Hier haben wir 2 Gerade die einen Winkel Bilden. Bei genauer Betrachtung gibt es 2 Winkel, einmal obenlinks einen Winkel < 180° und einen untenrechts > 180° Da wir den kleineren Winkel vergleichen wollen, berechnen wir beide und nehmen den kleineren.
Um die Unter-/Überschreitung von 0° bzw. 360° zu kompensieren nehmen wir das jeweilige Ergebnis % 360.0 Da
5 - 355 = -350
und
-350 % 360 = 10
ist.

Code: Alles auswählen

def etwa_gleich(testwinkel, winkel, plusminus):
    abstand1 = (testwinkel-winkel)%360.0
    abstand2 = (winkel-testwinkel)%360.0
    if abstand1 < abstand2:
        return abstand1 <= plusminus
    else:
        return abstand2 <= plusminus
Die if-Abfrage können wir auch durch die eingebaute Funktion min() ersetzen, die aus zwei oder mehr Werten den kleinsten zurückgibt

Code: Alles auswählen

def etwa_gleich(testwinkel, winkel, plusminus):
    abstand1 = (testwinkel-winkel)%360.0
    abstand2 = (winkel-testwinkel)%360.0
    return min(abstand1, abstand2) <= plusminus
Wenn wir jetzt noch auf die Variablen 'abstand1' und 'abstand2' verzichten und die Ausdrücke '(testwinkel-winkel)%360.0' und '(winkel-testwinkel)%360.0' direkt als Parameter an min() übergeben sind wir wieder bei meiner zuerst geposteten Lösung.

Zum Testen noch ein kleines Codestück:

Code: Alles auswählen

def test():
    for i in xrange(0, 360, 10):
        for j in xrange(0, 360, 10):
            print "etwa_gleich(%i, %i, 20) -> %s    " % (i, j, str(etwa_gleich(i, j, 20))),
        print

Gruß

Dookie

Verfasst: Mittwoch 17. November 2004, 22:30
von Dookie
Hi jens,
jens hat geschrieben: Wobei mir da eine Zwischenfrage an die Allgemeinheit einfällt: Warum kann man mit range() keine anderen Schrittwerte als Ganzzahlen verwenden??? Also sowas wie:

Code: Alles auswählen

range(0,10,0.1)
Weil range() bzw. xrange() auf Geschwindigkeit optimiert sind. Integerberechnungen sind eben um ein Vielfaches schneller als Floatingpointberechnungen. Im Übrigen lässt sich dein Beispiel ja auch einfach (wiedermal in einer Zeile ;) ) umsetzen.

Code: Alles auswählen

[x/10.0 for x in xrange(0, 100, 1)]
Gruß

Dookie

Verfasst: Mittwoch 17. November 2004, 23:19
von Kranioklast
@Dookie
Du bist offensichtlich ein Python-Genie...

Deine Ausführung hat mich beeindruckt, ich kann sie auch
nachvollziehen.

Aber bis ich alleine auf so etwas komme, ist es noch ein langer Weg.
Wenn überhaupt... :D

Danke an alle für ihre Erklärungen!!
Je simpler, desto besser! :D