python problem

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
Kranioklast
User
Beiträge: 14
Registriert: Dienstag 9. November 2004, 20:56
Wohnort: Berlin

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!
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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...
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

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
[code]#!/usr/bin/env python
import this[/code]
Kranioklast
User
Beiträge: 14
Registriert: Dienstag 9. November 2004, 20:56
Wohnort: Berlin

Vielen Dank!! Wenn ich stecken bleibe, melde ich mich wieder. :D
Kranioklast
User
Beiträge: 14
Registriert: Dienstag 9. November 2004, 20:56
Wohnort: Berlin

Was genau bewirkt denn das %?
Damit habe ich bisher noch nicht gearbeitet.

Danke!!
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

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
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

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
[code]#!/usr/bin/env python
import this[/code]
Kranioklast
User
Beiträge: 14
Registriert: Dienstag 9. November 2004, 20:56
Wohnort: Berlin

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
Christopy
User
Beiträge: 131
Registriert: Montag 15. Dezember 2003, 22:39

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... :(
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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)
fs111
User
Beiträge: 170
Registriert: Samstag 15. November 2003, 11:42
Kontaktdaten:

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
Pydoc-Integration in vim - Feedback willkommen: http://www.vim.org/scripts/script.php?script_id=910
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

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
[code]#!/usr/bin/env python
import this[/code]
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

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
[code]#!/usr/bin/env python
import this[/code]
Kranioklast
User
Beiträge: 14
Registriert: Dienstag 9. November 2004, 20:56
Wohnort: Berlin

@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
Antworten