Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - mod-Operator
knittel - Mi 21.08.13 01:44
Titel: mod-Operator
Hallo allerseits,
Ich hab um einen beliebigen Winkel in der Rahmen von 0 und 360 zu bringen den module Operator verwendet. Einfach result := Winkel mod 360.
Doch sobald es zu negativen Zahlen kommt, ist der Winkel stattdessen
Tranx - Mi 21.08.13 04:21
Bei x mod y bekommst Du nur ganzzahlige Werte, da Du nur ganzzahlige Werte einsetzen darfst. Aber unabhängig davon, mit
solltest Du das gewünschte Ergebnis bekommen.
Und für nicht integer:
Delphi-Quelltext
1:
| y := abs(x - int(x/360)*360); |
Boldar - Mi 21.08.13 06:03
oder aber
Delphi-Quelltext
1: 2:
| while (x<0) x:=x+360; x:=x mod 360; |
Für bessere Performance evtl. die 360 durch größere Zahlen ersetzen, z.B.
((maxint div 360)*360)
Gammatester - Mi 21.08.13 09:13
Tranx hat folgendes geschrieben : |
Delphi-Quelltext 1: 2: 3:
| y := abs(x) mod 360; y := abs(x - int(x/360)*360); | |
Die beiden Formeln sind alllerdings
offensichtlich falsch, da zB -30 nach 30 transformiert wird! Das bedeutet zB für den einfachen Sinus, das Du falsche Vorzeichen hast. Die einfachste und schnellste Möglichkeit nur mit Delphibordmitteln ist meiner Meinung nach
Delphi-Quelltext
1: 2:
| y := x - int(x/360.0)*360.0; if y < 0.0 then y := y + 360.0; |
jasocul - Mi 21.08.13 10:10
Habe nur ich das Gefühl, dass hier mit Kanonen auf Spatzen geschossen wir?
Delphi-Quelltext
1: 2: 3:
| NeuerWinkel := AlterWinkel mod 360; if NeuerWinkel < 0 then NeuerWinkel := NeuerWinkel + 360; |
Xion - Mi 21.08.13 11:17
Fast, ich würde sagen:
Delphi-Quelltext
1: 2: 3:
| NeuerWinkel := AlterWinkel mod 360; while NeuerWinkel < 0 do NeuerWinkel := NeuerWinkel + 360; |
Aber das hatte
Boldar schon so in etwa :mrgreen:
oder ganz ohne mod:
Delphi-Quelltext
1: 2: 3: 4:
| while NeuerWinkel >= 360 do NeuerWinkel := NeuerWinkel - 360; while NeuerWinkel < 0 do NeuerWinkel := NeuerWinkel + 360; |
Das Ding heißt übrigens nicht module sondern
modulo
jasocul - Mi 21.08.13 11:21
@Xion:
Das while ist unnötig, da das vorherige Modulo schon dafür sorgt, dass der neue Winkel im richtigen Bereich ist. :wink:
Gammatester - Mi 21.08.13 11:24
jasocul hat folgendes geschrieben : |
Habe nur ich das Gefühl, dass hier mit Kanonen auf Spatzen geschossen wir?
Delphi-Quelltext 1: 2: 3:
| NeuerWinkel := AlterWinkel mod 360; if NeuerWinkel < 0 then NeuerWinkel := NeuerWinkel + 360; | |
Richtig! Die Kanonen müssen ja auch nur dann zu Einsatz kommen, wenn die Winkel
keine Integer sind, was also wahrscheinlich meist der Fall ist, außer vielleicht für einzelne Spezialfragen oder eine Tabelle der von reduzierten Integerwinkeln :wink:
Xion - Mi 21.08.13 11:29
jasocul hat folgendes geschrieben : |
@Xion:
Das while ist unnötig, da das vorherige Modulo schon dafür sorgt, dass der neue Winkel im richtigen Bereich ist. |
Hmm, also das ist mir zu vage. Warum sollte ich nicht zweimal einen Winkel abziehen, bevor ich ihn wieder normalisiere? Das Modulo hat ja keinen Effekt bei negativen Zahlen (zumindest bei meinem Delphi bin ich mir da zu 99,9% sicher). So komm ich leicht auf -400 Grad. Mir ist da eine sichere, vielleicht minimal langsamere Variante doch lieber ;)
jasocul - Mi 21.08.13 11:58
@Gammatester:
Modulo ist für ganzzahligen Werte.
knittel nutzt das ja schon. Sollten allerdings auch nicht-ganzzahlige Typen verwendet werden, hast du natürlich Recht.
@Xion:
Bei XE2 funktioniert Modulo auch bei negativen Werten.
Tranx - Mi 21.08.13 12:47
Alternativ: Um die FALSCHE Formel zu verbessern:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| y := x mod 360; if y <0 then y := y + 360;
y := abs(x - int(x/360)*360); if y <0.0 then y := y + 360; |
knittel - Mi 21.08.13 13:09
ui^^ ne ganze Mengen Antworten. Danke an alle schonmal! :)
Es war zwar garnicht so sehr das Problem wie ich das löse, dafür verwende ich:
Delphi-Quelltext
1: 2: 3: 4: 5:
| function ClampToAngle(const A: single): single; begin result := Trunc(A) mod 360 + Frac(A); if result < 0 then result := result + 360; end; |
(auf while wollte ich aus Performance-Gründen verzichten)
Ich hab mich nur gefragt warum mod so arbeitet. Ich dachte immer mod würde (an einem Zahlenstrahl erklärt) so arbeiten:
x mod 4
Quelltext
1: 2:
| x: -9|-8|-7|-6|-5|-4|-3|-2|-1|0|1|2|3|4|5| y: 3| 0| 1| 2| 3| 0| 1| 2| 3|0|1|2|3|0|1| |
Gammatester - Mi 21.08.13 13:39
Tranx hat folgendes geschrieben : |
Alternativ: Um die FALSCHE Formel zu verbessern: Delphi-Quelltext 1: 2: 3: 4:
| y := abs(x - int(x/360)*360); if y <0.0 then y := y + 360; | |
Das ist nun definitiv Unsinn. y=abs() kann nicht negativ sein, also bringt die if-Anweisung überhaupt nichts, und -30 wird immer noch in +30 umgewandelt und nicht in 330.
Mathematiker - Mi 21.08.13 14:20
Hallo,
so ein ähnliches Problem kenne ich bei der Berechnung des Wochentages mit der Zellerschen Formel.
Meine Lösung war (auf Dein Problem angewendet):
Delphi-Quelltext
1: 2: 3: 4:
| result := (winkel + 360) mod 360; oder result := (winkel + 3600) mod 360; oder noch größere Summanden |
Da habe ich kein if, while usw. drin, sondern "nur" eine Addition.
Wahrscheinlich ist das wieder nicht so elegant, aber es funktioniert.
Beste Grüße
Mathematiker
Gammatester - Mi 21.08.13 14:42
Mathematiker hat folgendes geschrieben : |
Da habe ich kein if, while usw. drin, sondern "nur" eine Addition.
Wahrscheinlich ist das wieder nicht so elegant, aber es funktioniert. |
Wie wir inzwischen erfahren haben, will
knittel ja doch eigentlich Singlewinkel normalisieren und wählt einen Weg über trunc() mod 360 + frac(). Selbst wenn man Deinen Ansatz einsetzen würde, hätte man
Delphi-Quelltext
1:
| result := (Trunc(A) + 3600) mod 360 + Frac(A) |
Trotzdem käme man wegen des möglichen negativen Frac(A) praktisch nicht um ein
if herum, weil das Ergebnis noch negativ sein kann (oder man müßte noch mehr Aufwand treiben um ein
if zu vermeiden).
Tranx - Mi 21.08.13 15:03
Entschuldigung, dass ich das abs nicht gelöscht hatte
bei 30 ergibt das 30 - 360*0 = 30 bei -30 : 360 - 30 - 360*0 = 330
bei 750 ergibt das 750 - 360*2 = 30 bei -750: 360 - 750 - 360*-2 = 330
Das sollte nun korrekt sein.
IhopeonlyReader - Mi 21.08.13 15:17
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| NeuerWinkel := (Abs(Trunc(AltWinkel))-1) mod 360 +1; if AltWinkel<0 then NeuerWinkel := (360 - NeuerWinkel) + Frac(AltWinkel) else NeuerWinkel := NeuerWinkel + Frac(AltWinkel); if NeuerWinkel > 360 then NeuerWinkel := NeuerWinkel - 360 else if NeuerWinkel < 0 then NeuerWinkel := NeuerWinkel + 360; |
Ach ich liebe die Vielfalt der Mathematik :D
Gammatester - Mi 21.08.13 15:18
Langsam glaube ich auch an die Kanonen/Spatzen-Theorie von
jasocul. Alles wäre einfacher, wenn Delphi ein mathematisch korrektes
mod hätte, das auch für Fließkommazahlen definiert wäre, ähnlich
fmod in C. Man kann es natürlich mit
floor aus der Math-Unit nachbilden und hätte dann (ohne
if):
Delphi-Quelltext
1: 2: 3: 4:
| function ClampToAngle(const A: single): single; begin result := A - floor(A/360.0)*360.0; end; |
IhopeonlyReader - Mi 21.08.13 15:21
ok, gammatester hat wohl damit den thread beendet :D
das ist die einfachste und warscheinlich schnellste methode
Gammatester - Mi 21.08.13 15:26
IhopeonlyReader hat folgendes geschrieben : |
Gammetester.. es bleibt dabei -0,12° <> 0,12° sondern = 359,88° ! |
Huh :autsch: Meine Funktion liefert die 359,88°, vielleicht hast Du nicht mitbekommen, daß 0,12° nicht das gewünschte Ergebnis ist. - Oder ich bin im Tran und mache dann besser Schluß für heute.
(Noch'n Mist): Ist wohl durch ein Edit von
IhopeonlyReader überholt.
IhopeonlyReader - Mi 21.08.13 16:22
sorry :D ja ist überholt ;)
knittel - Mi 21.08.13 23:03
Die Lösung von Gammatester ist glaube ich wirklich die beste, das richtige Ergebnis liefern auf jeden Fall beide (Gammatesters und meine, die meisten anderen sehen etwas umständlich aus :gruebel: )
P.S. Hab mal nen Performance Check gemacht, Gammatesters Variante braucht nur 80% von der Zeit, die mein Befehl braucht, ist also ein gutes Stück schneller. Danke! :)
IhopeonlyReader - Do 22.08.13 00:26
Meins ist falsch? Was denn? Die Werte die ich getestet habe klappten :O
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!