TIA modulo liefert falsches Ergebnis (V16)

Zuviel Werbung?
-> Hier kostenlos registrieren
1 mod 5 = -1 (sind die doof???
Also ich kenne Module als: Teile durch Zahl x und liefere den Rest, demnach also vollkommen korrekt.
Jein.
Das ist zwar eine möglich Lösung, aber nicht die in der Mathematik bevorzugte und vor allem die bei den von den Kollegen aufgeführten Ringregistern gewünschte:
...
Zur Normierung wird in der Mathematik die Konvention verwendet, die Vorzeichen der Reste aus denen der Teiler zu beziehen, wie in den folgenden Beispielen dargestellt:
Demnach ist in der Mathematik -1 MOD 5 = 4.
 
IF..THEN(-Orgien) erscheinen Programmierern, die überwiegend nur in Hochsprache programmieren (können), natürlich nicht als "umständlich". ;) Es schadet aber trotzdem nicht, wenn man ein paar solche grundlegenden und bewährten Algorithmen kennt (und anwendet). Besonders wenn man unbedingt effizienten/schnellen Code programmieren will/muss.
(Für SPS und den Mini-Code hier eher nicht relevant: Bedingte Programmzweige sind z.B. Gift für den Prozessor-Befehls-Cache und parallele Codeausführung.)

Die Einzeiler mit MOD kann man auch einfach in FUP/KOP programmieren. Versucht das mal mit der IF-Variante ... das wird sehr "umständlich".
Gibt es auch unbedingte Programmzweige?

Man sollte sich wirklich sicher sein, wann es sich lohnt eine Funktion auf dieser Ebene zu optimieren, denn besser lesbarer ist ein If/Then in den meisten Fällen, weil jeder direkt erkennen kann was wann passiert und nicht erst rechnen muss.

Um zu wissen ob sich es "lohnt" die Lesbarkeit der Laufzeit zu opfern, müsste man auch genau wissen welche Laufzeit welche Anweisung auf dem jeweiligen Zielsystem besitzt. Und wenn das Ganze wie in einer SPS wahrscheinlich in einem Interpreter oder in einer Sandbox auf einem unbekannten Prozessor läuft, dann sind jegliche Überlegungen bezüglich Branch-Prediction, Pipelines usw. generell hinfällig, weil das ganz anders funktioniert und abhängig vom Interpreter ist.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Gibt es auch unbedingte Programmzweige?
:unsure: Hmmm. Im Prinzip ja, aber als Zweige (branches) würde man sie dann nicht bezeichnen. ;)

Mal etwas provokant gefragt:
Warum muss man "künstliche" FallUnterscheidungen programmieren an Stellen, wo es eigentlich gar keine gibt, sondern eine ganz simple Regel genügt?
Warum eine Regel nicht einfach so formulieren, dass die Anzahl der zu berücksichtigenden "Ausnahmen" nicht von vornherein unnötig aufgebläht wird?
Warum nicht akzeptieren, dass wir unsere zu komplizierte "Alltags"-Denkweise nicht mit aller Gewalt 1:1 in einem ComputerProgramm nachbilden/abbilden müssen?
 
Ein If/Then sagt doch genau das was es soll: Wenn Wert größer X dann das machen, wenn nicht, dann das, und das könnte ein Compiler sogar erkennen. Bei einer Modulo Division muss ich überlegen, was will jemand mit dem Rest denn nun anstellen.

Üblicherweise optimieren zumindest aktuelle C/C++ Compiler so gut, dass es nur in Ausnahmefällen sinnvoll ist da in den Assemblercode Einblick zu nehmen um da ggf. noch händisch etwas zu optimieren. Beispielsweise gibt es auch noch eine Abkürzung für Modulo-Rechnungen mit Zweierpotenzen. Baut man das im SPS Programm jetzt auch noch ein, weil wenn MOD schon 1-2 Zyklen gegenüber einem Sprung spart und ein AND nochmal 1 Zyklus, warum macht man es dann nicht im Ausnahmefall auch damit um auch das letzte Fitzelchen rauszukitzeln?
 
Nun könnte man auch hier umständlich programmieren:
Code:
nextIndex := currentIndex - 1;
IF nextIndex < 0 THEN
  nextIndex := ArraySize - 1;  //Ring: Vorgänger des ersten Elements ist das letzte Element!
END_IF;
Warum muss man "künstliche" FallUnterscheidungen programmieren an Stellen, wo es eigentlich gar keine gibt, sondern eine ganz simple Regel genügt?
Richtig.

Für die IF-Verfechter: Was sollte man machen, wenn man nicht nur genau 1 Position rückwärts rechnen will, sondern eine variable Anzahl, z.B. bis zu einer halben Drehtisch-Umdrehung? Will man da für jedes mögliche negative Ergebnis eine eigene IF-Regel programmieren??! Oder ..zig CASE-Fälle? Spätestens bei der vierten Sonderbehandlung verliert der Programmierer die Lust auf sooo viel Schreibarbeit und es fällt ihm auf, daß man die "Sonderfälle" zusammenfassen kann:
Code:
Destination := currentPos - Distance;  // Rückwärtsdrehung

IF Destination < 0 THEN
  Destination := ArraySize + Destination;  // kann man vertauschen: Destination := Destination + ArraySize;
END_IF;
Ist das nun wirklich noch viel verständlicher als die einfache MOD-Formel?


Vielleicht möchte man das auch noch zu einem Code zusammenfassen, der sowohl Vorwärts- als auch Rückwärts-Drehungen berechnen kann?
Code:
Destination := currentPos + Distance;  // Vorwärts: Distance positiv (> 0), Rückwärts: Distance negativ (< 0)

IF Destination >= ArraySize THEN
  Destination := Destination - ArraySize;  // <--- Aha!!
END_IF;

IF Destination < 0 THEN
  Destination := Destination + ArraySize;  // <--- Aha!!
END_IF;

Die einfache Formel mit der Addition des Modulo-Wertes und MOD berechnet ALLE Fälle richtig, ganz ohne Sonderbehandlungen:
Code:
Destination := (currentPos + Distance + ArraySize) MOD ArraySize;


Noch ein +Punkt: für die IF-Lösung mit Sonderbehandlung müssen Berechnungs-Zwischenergebnisse abgespeichert werden, bei der MOD-Formel nicht. Die MOD-Formel eignet sich dadurch auch als Teil einer längeren Formel ohne zwischendurch speichern zu müssen, z.B. um die Speicheradresse eines DINT-Array-Elements zu berechnen:
ArrayOffset := ((currentPos + Distance + ArraySize) MOD ArraySize) * 4;

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die if Abfrage war auch nur auf auf diesen einen einfachen Fall bezogen:

Code:
nextIndex := currentIndex - 1;
IF nextIndex < 0 THEN
  nextIndex := ArraySize - 1;  //Ring: Vorgänger des ersten Elements ist das letzte Element!
END_IF;

Dafür finde ich die Abfrage durchaus ok.

Das Thema "mod vs. If..then..else" jetzt noch künstlich auf die Spitze zu treiben und in einen Glaubenskrieg ausarten zu lassen, muss nicht sein. Ist vielleicht auch eher eine Frage des persönlichen stil.

Ich habe zumindest was über die Benutzung von mod gelernt (y)
 
Ein versöhnlicher Abschluss, oder?
Und damit es auch noch etwas zum Schmunzeln gibt:
Wie wäre es, beides miteinander zu kombinieren, ganz ohne MOD und IF THEN?
Code:
Destination:=CurrentPos+Distance+(BOOL_TO_INT((CurrentPos+Distance)<0)-BOOL_TO_INT((CurrentPos+Distance)>=ArraySize))*ArraySize;
 
C hat für solche Einzeiler-Lösungen den ternären Operator, der einerseits obskur aber andererseits wirklich nützlich ist, z.B. wenn man bei String-Ausgaben optional ein Plural-s anhängen möchte.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
C hat für solche Einzeiler-Lösungen den ternären Operator, der einerseits obskur aber andererseits wirklich nützlich ist ...
Kennt man von Excel, heisst dort 'WENN' und ist dort alles andere als obskur.
Aber dort benötigt man ihn NICHT, um die Funktionsweise von Modulo (in Excel: 'REST') zu "reparieren" - 'REST' verhält sich schon genau so, wie Mario das auch bei TIA V16 von 'MOD' erwartet hatte. ;)
 
@ PN/DP
Die einfache Formel mit der Addition des Modulo-Wertes und MOD berechnet ALLE Fälle richtig, ganz ohne Sonderbehandlungen:


Code:

Destination := (currentPos + Distance + ArraySize) MOD ArraySize;
Und genau das ist nicht richtig!
Dies stimmt nur solange
Code:
 (currentPos + Distance + ArraySize)
positiv ist!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es geht hier doch garnicht wer recht hat... Irgendwann schaut ein armer Tropf hier rein, weil er eben dieses Problem hat, sieht eine Lösung die "immer Funktioniert" und fällt damit voll auf die Schnauze weil er es einfach nicht durchblickt...
 
@ PN/DP

Und genau das ist nicht richtig!
Dies stimmt nur solange
Code:
 (currentPos + Distance + ArraySize)
positiv ist!
Ja, aber damit es positiv ist (wird), wird doch gerade ArraySize hinzuaddiert. Das Ergebnis kann ja nur negativ sein, wenn |current + Distance| > ArraySize und negativ ist. currentPos ist das Ergebnis der Modulo-Rechnung, das gar nicht negativ sein darf. Also bleibt nur noch Distance. Der Betrag von Distance müsste also größer als currentPos + ArraySize sein und negativ sein. Das sollte nur auftreten, wenn man >1 Umdrehung ins Negative fahren will. In diesem Spezialfall müsste man
CSS:
currentPos + Distance + (cntRound * ArraySize) // cntRount = Anzahl Runden
rechnen.
An dieser Stelle kann man sagen Excel sticht TIA :cool:

VG

Mario
 
Zuletzt bearbeitet:
Es geht hier doch garnicht wer recht hat... Irgendwann schaut ein armer Tropf hier rein, weil er eben dieses Problem hat, sieht eine Lösung die "immer Funktioniert" und fällt damit voll auf die Schnauze weil er es einfach nicht durchblickt...
Moin NBerger,

ja, und deshalb finde ich es auch wichtig, dass wir das Thema hier bis ins Kleinste durchkauen. Doof ist es immer nur, wenn sich ein Thema Offtopic dynamisiert.
Aber ich bin auch schon auf einige Threads gestoßen, bei denen ich dachte: ah, das kann mir helfen. Aber nach ein paar Posts bricht die Anlayse ab und man steht mit einem halbfertigen Ergebnis da.
Dass das Problem besteht, sieht man an der Menge alter Threads, die nach Jahren wieder aufgerollt werden.

Insofern freue ich mich über den konstruktiven, fachlichen Austausch (y)

VG

Mario
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Aber ich bin auch schon auf einige Threads gestoßen, bei denen ich dachte: ah, das kann mir helfen. Aber nach ein paar Posts bricht die Anlayse ab und man steht mit einem halbfertigen Ergebnis da.
Ja leider. Manche Threads kommen sogar nie oder erst nach mehreren Jahren (!) in Gang.
Viele Threads verlaufen sehr schnell im Sand, statt sich zu entwickeln und oft scheitert es daran, dass sich der TE gar nicht mehr am Thread beteiligt.
Manchmal hapert es daran, dass sich der TE zwar noch beteiligt, aber konsequent den Rückfragen/Gegenfragen ausweicht.
Und es ist manchmal sooo verlockend, ein OffTopic zu starten und erst recht, auf einen in Schwung gekommenen OffTopic aufzuspringen ...
 
Man kann doch auch zum Ergebnis der Modulo-Anweisung den Divisor addieren, falls das Ergebnis negativ ist. Ich denke das ist einfacher und verständlicher.
 
Man kann doch auch zum Ergebnis der Modulo-Anweisung den Divisor addieren, falls das Ergebnis negativ ist.
Genau das hilft in S7 und Codesys wegen dem hier diskutierten speziellen Verhalten der MOD-Anweisung eben nicht. Da muß der Divisor vor der MOD-Anweisung addiert werden.
Falls jemand Angst hat, daß der Eingangswert mehr negativ als der Divisor sein könnte, dann kann man auch z.B. "verständlich" in einer Schleife so oft den Divisor addieren bis der Wert Positiv ist.

Harald
 
Zurück
Oben