TIA modulo liefert falsches Ergebnis (V16)

Zuviel Werbung?
-> Hier kostenlos registrieren
Moin,

ich habe mich noch einmal mit einem DiplomMathematiker ausgetauscht.

Letzten Endes ist das kein mathematisches Problem. Wie die Restberechnung umgesetzt wird ist die Sache Desjenigen, der die Funktion anbietet. Deswegen hat SIEMENS auch nichts „falsch“ gemacht. Sie haben ja auch beschrieben, wie „ihre“ ModuloFunktion arbeitet.
Es war halt einfach nicht das, was ich erwartet hatte. Aber jetzt bin ich ja schlauer 😉.

Meine Lösung sieht jetzt zumindest so aus. Damit bin ich gut zufrieden:

Code:
Wert := (Wert + Devisor + Inkrement) mod Devisor; // Inkrementieren
Wert := (Wert + Devisor - Inkrement) mod Devisor; // Dekrementieren

VG

Mario
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich verwende die Modulofunktion oft, wenn ich z.Bsp. einen Umlauf für ein Register benötige. Dann natürlich ausschließlich mit positiven Zahlen. Bei was für Anwendungen kommt man denn in die Verlegenheit, die Modulofunktion auf negative Zahlen zu verwenden? Kann mal jemand einen einfachen Anwendungsfall schildern?
 
Bei was für Anwendungen kommt man denn in die Verlegenheit, die Modulofunktion auf negative Zahlen zu verwenden?
Wenn man bei etwas "Rundem" (*) rückwärts durchfährt und nach der 0-Position kommt man wieder an die höchste Position. Oder bei einem Encoder fährt man rückwärts über die 0-Position.

(*) Drehtisch, Magazin, Uhrzeiger, Ringpuffer, Listen ...

Harald
 
Moin,

zum einen nutze ich es, um einen FIFO (20 Einträge) mit einem Ausschnitt von einem Ringpuffer (500 Einträge) zu füllen.
Wir erzeugen Meldungen per Program_Alarm. Ein Partner liest die Meldetexte per OPC UA aus einem Ringpuffer aus. Um dem Partner (PC-System) die Meldetexte zu übermitteln, lesen wir die Meldungen mit GetAlarm aus und tragen sie in einen Ringpuffer (DB) ein.
Jetzt hatten wir mal ein Basic-Panel….
Kann also keine Program_Alarm-Meldungen anzeigen. Dafür dann das Auslesen von 20 Einträgen aus dem Ringpuffer und Eintragen in den FIFO. Im Basic-Panel einfach 20 E/A-Felder untereinander. Fertig ist die Meldeanzeige.

Jetzt brauchte ich es akut für eine Spieleprogrammierung „fleißige Bieber“:
Um diese Inhalte anzuzeigen, benötigen wir die Zustimmung zum Setzen von Drittanbieter-Cookies.
Für weitere Informationen siehe die Seite Verwendung von Cookies.
Ab 1:00:00.
Damit die Lokomotive in beide Richtungen wieder in der anderen Ecke weiterfahren kann.

VG
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn man bei etwas "Rundem" (*) rückwärts durchfährt und nach der 0-Position kommt man wieder an die höchste Position. Oder bei einem Encoder fährt man rückwärts über die 0-Position.

(*) Drehtisch, Magazin, Ringpuffer, Uhrzeiger, ...

Harald
Na, oder so (hatte ich nur noch nicht)
 
Wenn man bei etwas "Rundem" (*) rückwärts durchfährt und nach der 0-Position kommt man wieder an die höchste Position. Oder bei einem Encoder fährt man rückwärts über die 0-Position.

(*) Drehtisch, Magazin, Uhrzeiger, Ringpuffer, Listen ...

Harald
Kannst du das genauer erklären bitte? Kann mir nicht vorstellen wie oder wo man das braucht? Evtl. ein kurzes Codebeispiel?
 
Na, der Code wurde doch bereits aufgeschrieben.

Aber Du hast ja nach einer (näher beschriebenen) Anwendungen gefragt:

Wenn ich z.B. ein rundes Magazin habe und den kürzesten Weg von dem aktuellen Magazin-Fach zu einem (auf dem Kreis liegenden) anderen Magazin-Fach suche, komme ich ggf. durch den „Nulldurchgang“. Bei Gradzahlen wäre das 359->0 oder 0->359. Bei 0->359 habe ich genau den Problemfall in der Modulo-Berechnung.
Weitere Beispiele hatte ich ja schon genannt.

VG
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Weiteres Beispiel:

Wenn man in einem als Ring organisierten 0-basierten Array [0..(ArraySize-1)] den Index des nächsten Elements berechnen will, und nach dem letzten Element soll wieder das erste Element adressiert werden, dann kann man schreiben:
Code:
nextIndex := currentIndex + 1;
IF nextIndex >= ArraySize THEN
  nextIndex := 0;              //Ring: Nachfolger des letzten Elements ist das erste Element!
END_IF;
Oder einfacher ohne IF und ohne bedingte Sprünge:
Code:
nextIndex := (currentIndex + 1) MOD ArraySize;  //liefert "rechten" Nachfolger im Ring

Wenn man nun auch rückwärts durch das Array gehen will, dann könnte man auf die Idee kommen:
Code:
nextIndex := (currentIndex - 1) MOD ArraySize;
Und hier bekommt man das Problem, daß beim untere Überlauf "(0 - 1) MOD ArraySize" nicht ArraySize-1 ergibt (wie man vlt. erwarten könnte)! Das bemerkt man dann, wenn man den Code auch bei den Überläufen testet. ;)

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;
oder einfach vor dem MOD einmal (oder auch mehrmals) ArraySize addieren:
Code:
nextIndex := (currentIndex + ArraySize - 1) MOD ArraySize;  //liefert "linken" Vorgänger im Ring
oder
Code:
maxIndex := ArraySize - 1;
...
nextIndex := (currentIndex + maxIndex) MOD ArraySize;  //liefert "linken" Vorgänger im Ring

Immer wenn die Gefahr besteht, daß der Eingangswert für MOD negativ werden kann, dann verschiebt man einfach den Eingangswert auf dem Zahlenstrahl um ArraySize in den positiven Bereich - also ArraySize dazuaddieren. Bei MOD kann man übrigens "beliebig" oft ArraySize auf den Eingangswert addieren (max-Wert des Datentyps beachten!) ohne daß es das Ergebnis vom MOD beeinflußt! :cool: Das kann man sich wie mehrere ganze Umdrehungen des Rings vorstellen.

Harald
 
Danke Harald für die ausführliche Erklärung. Aber die zwei IF-ELSE als umständlich zu bezeichnen verstehe ich nicht. Ich denke die IF-ELSE Variante ist deutlich einfacher und leichter lesbar. Bei der kämen auch solche Themen wie dieses nicht auf, da man nicht Herstellerabhängig den Code ändern müsste.
 
Danke, die Möglichkeiten mit mod habe ich noch nie bedacht. Allerdings finde ich die zwei if Abfrage auch nicht als umständlich. Ich persönlich empfinde die auch als besser lesbar.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich denke die IF-ELSE Variante ist deutlich einfacher und leichter lesbar. Bei der kämen auch solche Themen wie dieses nicht auf, da man nicht Herstellerabhängig den Code ändern müsste.
Ich sehe das eigentlich auch so, aber:
1) Verständlichkeit liegt in der Denkweise des Betrachters.
2) Je häufiger man eine bestimmte Problemlösung benötigt, um so eher erliegt man dem Charme von Einzeilern.

Eine Codeanpassung ist übrigens nicht notwendig. Unterschiedliche Umsetzungen der MOD-Operation wirken sich nur bei der Anwendung von MOD auf negative Werte aus, und genau das wird ja durch die Addition der Ringpuffergrösse verhindert.
 
Ich hab sowas bisher immer mit If ... Then ... Else programmiert, daher kam mit der Fehler diese Verhalten ;) wohl noch nicht unter. Da meine derzeitige Endlos-Taktkette mit Servopositionierung per Hand auch Rückwärts gedreht werden kann, hätte ich hier mit Mod auch ein Problem gehabt.
 
die zwei IF-ELSE als umständlich zu bezeichnen verstehe ich nicht.
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".

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
IF..THEN(-Orgien) erscheinen Programmierern, die überwiegend nur in Hochsprache programmieren (können), natürlich nicht als "umständlich". ;)
Und nicht jeder, der ausgiebig mit IF..THEN programmiert, ist sich darüber im Klaren, was er damit u.U. anrichtet.
Wie hier im Forum schon des öfteren zu beobachten war, wird z.B. schon mal der ELSE-Zweig (unabsichtlich) geschlabbert und sich dann gewundert, dass der Code nicht das Beabsichtigte leistet.
Selbstverständlich soll man lesbar und verständlich programmieren. Aber man kann und darf dabei nicht auf hier und da fehlende Grundkenntnisse eventueller "Leser" Rücksicht nehmen.
 
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".

Harald
Wobei nicht sicher ist, ob mod wirklich effizienter als ein (in diesem Fall) einziges If ... Then ... Else ist. Orgie?? NA ja... Aber so effizeient brauchen wir es i.d.R. nicht mehr, die Steuerungen sind inzwischen für alltägliche Dinge schnell genug, wenn man grundsätzlich zur Kleinsten greift.
 
Zurück
Oben