1..24 umcodieren in Kombination von 4 Ziffern

Zuviel Werbung?
-> Hier kostenlos registrieren
Da nun die String-Trickserei entfällt, dürfte sich die VBA-Rechnerei wesentlich leichter in SCL umschreiben lassen.
Ich werde mich daran auch noch versuchen ...
Habe ich mittlerweile (wie immer ungestestet):
Code:
' // kompl. Permutation (Beispiel für 5-stellige Permutationen)

CONST
    maxcol : INT   := 5 ;           // Anzahl Stellen der Permutation
    maxidx : INT   := maxcol - 1 ;  // für die Dimensionierung des Array
END_CONST

VAR_INPUT                       
    idx1   : INT   ;                // 1..maxcol!
END_VAR

VAR_TEMP
    idx0   : INT   ;                // 0..(maxcol! - 1)
    col    : INT   ;                // aktuelle Stelle/Spalte; Zählung beginnt rechts mit 1
    tmp    : INT   ;
    ord    : INT   ;                // OrdnungsZahl 0..4 für die berechnete Ziffer für die gegebene Stelle und den gegebenen Index
    idx    : INT   ;                // Array-Index             
    arr    : ARRAY [0..maxidx] OF BYTE := 5, 4 , 3 , 2 ,1 ; // "niederwertigste" Permutation
END_VAR

idx0 = idx1 - 1 ;

FOR col := maxcol TO 2 BY -1 DO

    ord := (idx0 / Fakultaet(col - 1)) MOD col ;
    tmp := arr(col - 1 - ord) ;
    FOR idx = col - 1 - ord TO col - 2 DO    // (Schleife darf nicht ausgeführt werden, wenn col - 1 - ord > col - 2 ist)
         arr(idx) = arr(idx + 1) ;
    END_FOR ;
    arr(col - 1) = tmp ;

END_FOR ;

// Die Elemente des Array enthalten jetzt die gesuchte Permutation ...
// ... aber wohin damit? Keine Ahnung. So gesehen war die StringVariante doch einfacher.
Den blöden Kommentar "(Schleife darf nicht ausgeführt werden, wenn col - 1 - ord > col - 2 ist)" habe ich eingefügt, weil ich nicht weiss, wie sich FOR in SCL verhält :unsure: und andernfalls Mehraufwand erforderlich ist.
 
Zuletzt bearbeitet:
Noch ein Aspekt: wenn man die mehreren Werte in mehrere verschiedene Variablen eingibt, dann ist bei der HMI-Kommunikation nicht garantiert daß die Werte gleichzeitig konsistent im selben Zyklus in der SPS ankommen.

Zur Not kann man die 4 Ziffern im HMI zu einer 4-stelligen Zahl kombinieren
 
Hier mal eine "Bitschubser" Version ohne Schleifen in SCL.
FUNCTION "permut" : Int
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
VAR_INPUT
index : Int;
END_VAR

VAR_TEMP
tPerm : Word;
atPerm AT tPerm : Array[0..15] of Bool;
tindex : Byte;
atindex AT tindex : Array[0..7] of Bool;
END_VAR


BEGIN
IF #index>12 THEN
#tindex := INT_TO_BYTE(IN := 24 - #index);
#atPerm[5] := 1;
ELSE
#tindex:=INT_TO_BYTE(IN :=#index-1);
#atPerm[5] := 0;
END_IF;
#atPerm[4] := #atindex[3] OR (#atindex[2] AND #atindex[1]);
#atPerm[1] := #atindex[3] OR (NOT #atindex[2] AND #atindex[1]) OR (#atindex[2] AND NOT #atindex[1]);
#atPerm[0] := (NOT #atindex[3] AND NOT #atindex[1]) OR (#atindex[3] AND #atindex[1]);
#atPerm[13] := #atindex[0] OR (#atindex[2] AND #atindex[1]) OR (NOT #atindex[3] AND NOT #atindex[2] AND NOT #atindex[1]);
#atPerm[12] := (NOT #atindex[2] AND NOT #atindex[1] AND #atindex[0]) OR (NOT #atindex[3] AND NOT #atindex[2] AND #atindex[1]) OR (NOT #atindex[3] AND #atindex[1] AND #atindex[0]) OR (#atindex[2] AND NOT #atindex[1] AND NOT #atindex[0]);
#atPerm[9] := NOT #atindex[0] OR (#atindex[2] AND #atindex[1]) OR (NOT #atindex[3] AND NOT #atindex[2] AND NOT #atindex[1]);
#atPerm[8] := (NOT #atindex[2] AND NOT #atindex[1] AND NOT #atindex[0]) OR (NOT #atindex[3] AND NOT #atindex[2] AND #atindex[1]) OR (NOT #atindex[3] AND #atindex[1] AND NOT #atindex[0]) OR (#atindex[2] AND NOT #atindex[1] AND #atindex[0]);
IF #index > 12 THEN
#tPerm := #tPerm XOR 16#1333;
END_IF;
#permut :=DINT_TO_INT(IN:= BCD32_TO_DINT(IN := #tPerm))+1111;
END_FUNCTION
EDIT: Wenn man sich nicht an langen Produkttermen stört, geht das auch ganz linear ohne IF.
#tindex := INT_TO_BYTE(IN := #index);
#atPerm[0] := (NOT #atindex[3] AND NOT #atindex[1] AND #atindex[0]) OR (NOT #atindex[3] AND #atindex[1] AND NOT #atindex[0]) OR (NOT #atindex[3] AND NOT #atindex[2] AND NOT #atindex[1]) OR (#atindex[3] AND #atindex[1] AND #atindex[0]) OR (#atindex[3] AND #atindex[2] AND NOT #atindex[1] AND NOT #atindex[0]);
#atPerm[1] := (#atindex[4] AND #atindex[3]) OR (#atindex[3] AND NOT #atindex[2] AND #atindex[0]) OR (#atindex[3] AND NOT #atindex[2] AND #atindex[1]) OR (NOT #atindex[4] AND NOT #atindex[2] AND #atindex[1] AND #atindex[0]) OR (NOT #atindex[4] AND NOT #atindex[3] AND #atindex[2] AND NOT #atindex[1]) OR (NOT #atindex[4] AND NOT #atindex[3] AND #atindex[2] AND NOT #atindex[0]) OR (NOT #atindex[4] AND #atindex[2] AND NOT #atindex[1] AND NOT #atindex[0]) OR (#atindex[4] AND NOT #atindex[2] AND NOT #atindex[1] AND #atindex[0]) OR (#atindex[4] AND NOT #atindex[2] AND #atindex[1] AND NOT #atindex[0]) OR (#atindex[4] AND #atindex[2] AND #atindex[1] AND #atindex[0]);
#atPerm[4] := (#atindex[3] AND NOT #atindex[2]) OR (#atindex[4] AND #atindex[2]) OR (#atindex[3] AND NOT #atindex[1] AND NOT #atindex[0]) OR (#atindex[4] AND #atindex[1] AND #atindex[0]) OR (NOT #atindex[3] AND #atindex[2] AND #atindex[1] AND #atindex[0]);
#atPerm[5] := #atindex[4] OR (#atindex[3] AND #atindex[2] AND #atindex[0]) OR (#atindex[3] AND #atindex[2] AND #atindex[1]);
#atPerm[8] := (NOT #atindex[4] AND #atindex[2] AND #atindex[1]) OR (NOT #atindex[2] AND NOT #atindex[1] AND #atindex[0]) OR (#atindex[2] AND #atindex[1] AND #atindex[0]) OR (#atindex[3] AND NOT #atindex[1] AND #atindex[0]) OR (NOT #atindex[4] AND NOT #atindex[3] AND NOT #atindex[2] AND #atindex[0]) OR (NOT #atindex[3] AND #atindex[2] AND NOT #atindex[1] AND NOT #atindex[0]);
#atPerm[9] := (NOT #atindex[4] AND #atindex[0]) OR (NOT #atindex[4] AND NOT #atindex[3] AND NOT #atindex[2]) OR (NOT #atindex[4] AND NOT #atindex[2] AND NOT #atindex[1]) OR (NOT #atindex[2] AND #atindex[1] AND #atindex[0]) OR (#atindex[2] AND NOT #atindex[1] AND #atindex[0]);
#atPerm[12] := (NOT #atindex[2] AND NOT #atindex[0]) OR (NOT #atindex[3] AND NOT #atindex[2] AND #atindex[1]) OR (#atindex[3] AND #atindex[1] AND NOT #atindex[0]) OR (NOT #atindex[4] AND NOT #atindex[3] AND #atindex[2] AND NOT #atindex[1]) OR (NOT #atindex[4] AND #atindex[2] AND NOT #atindex[1] AND #atindex[0]);
#atPerm[13] := (NOT #atindex[4] AND NOT #atindex[0]) OR (#atindex[2] AND NOT #atindex[0]) OR (NOT #atindex[3] AND NOT #atindex[1] AND NOT #atindex[0]) OR (NOT #atindex[4] AND NOT #atindex[3] AND #atindex[2] AND #atindex[1]) OR (NOT #atindex[4] AND NOT #atindex[3] AND NOT #atindex[2] AND NOT #atindex[1]);
#permut := DINT_TO_INT(IN := BCD32_TO_DINT(IN := #tPerm))+1111;
 
Zuletzt bearbeitet:
Hier mal eine "Bitschubser" Version ohne Schleifen in SCL.
Leider kann ich das Progrämmchen nicht testen und die BitSchubsereien waren mir anfangs zu mühsam *), sie nachzuvollziehen.
Was mir gefällt ist die Ausnutzung der "Symmetrie" und die damit verbundene "Nicht-Einsparung" der IF-Abfragen.
Ich finde aber, dass Du die Symmetrie nicht konsequent ausgenutzt hast, insofern ...
- Du #atPerm[5] := x mit in die If-Abfrage einbezogen hast und
- #tPerm := #tPerm XOR 16#1333; vermutlich haarscharf daneben sein dürfte.
Ich hätte 16#3333 genommen und #atPerm[5] := 0 ... unabhängig von Index > 12.

Habe versucht Deine Fassung ein wenig augenfreundlicher umzugestalten.
Und die Verknüpfungen zu vereinfachen (mit XOR) ... wodurch leider die Augenfreundlichkeit wieder nachgelassen hat ;) :
Code:
BEGIN
IF #index > 12 THEN
    #tindex     := INT_TO_BYTE(IN := 24 - #index) ; // Zuweisung #atPerm[5] verlegt, s.u. D1
ELSE
    #tindex     := INT_TO_BYTE(IN := #index - 1) ;  // Zuweisung #atPerm[5] verlegt, s.u. D1
END_IF ;

//                  -   -  D1  D0    -   -  C1  C0     -   -  B1  B0    -   -  A1  A0
//  #atPerm[]      [7] [6] [5] [4]  [3] [2] [1] [0]   [F] [E] [D] [C]  [B] [A] [9] [8]

//                  -   -   -   -    d   c   b   a
//  #atindex[]     [7] [6] [5] [4]  [3] [2] [1] [0]

//  D1 = 0
#atPerm[5]  :=      0 ;                 // hinzugefügt
//  D0 = d + cb
#atPerm[4]  :=      #atindex[3]
            OR      #atindex[2] AND      #atindex[1] ;
//  C1 = d + /cb + c/b
//     = d + (c # b)                    // # : XOR       
#atPerm[1]  :=      #atindex[3]
            OR     (#atindex[2] XOR      #atindex[1]) ;
//  C0 = /d/b + db
//     = /d # b                         // # : XOR
#atPerm[0]  :=  NOT #atindex[3] XOR      #atindex[1] ;
//  B1 = a + cb + /d/c/b           
#atPerm[13] :=      #atindex[0]
            OR      #atindex[2] AND      #atindex[1]
            OR  NOT #atindex[3] AND  NOT #atindex[2] AND  NOT #atindex[1] ;
//  B0 = /c/ba + /d/cb + /dba + c/b/a
//     = /b*(c # a) + /db*(/c + a)      // # : XOR        
#atPerm[12] :=  NOT #atindex[1] AND     (#atindex[2] XOR      #atindex[0])
            OR  NOT #atindex[3] AND      #atindex[1] AND (NOT #atindex[2] XOR     #atindex[0]) ;
//  A1 = /a + cb + /d/c/b          
#atPerm[9]  :=  NOT #atindex[0]
            OR      #atindex[2] AND      #atindex[1]
            OR  NOT #atindex[3] AND  NOT #atindex[2] AND  NOT #atindex[1] ;
//  A0 = /c/b/a + /d/cb + /db/a + c/ba
//     = /db*(/c + /a) + /b*(/c # a)    // # : XOR        
#atPerm[8]  :=  NOT #atindex[3] AND      #atindex[1] AND (NOT #atindex[2] OR  NOT #atindex[0])
            OR  NOT #atindex[1] AND (NOT #atindex[2] XOR      #atindex[0]) ;

IF #index > 12 THEN
    #tPerm := #tPerm XOR 16#3333 ; // warum zuvor 16#1333 und bedingte Zuweisung von #atPerm[5] ?
END_IF ;

#permut := DINT_TO_INT(IN := BCD32_TO_DINT(IN := #tPerm)) + 1111 ;
END_FUNCTION
Ich hatte einen ganz ähnlichen Ansatz begonnen und wieder verworfen, weil er für meinen Geschmack zu sehr auf die Permutationen von 4 Zeichen spezialisiert war und weil ich die Verwendung einer Schleife für flexibler und "näher an einem Algorithmus" gehalten habe.
Ein Bestandteil meines Ansatzes war, intern nicht den IndexBereich 1..12 bzw. 0..11, sondern 2..13 zu verwenden, weil ich dachte/hoffte damit die WahrheitsTabelle etwas vereinfachen zu können. Aber wenn ich das EinsparPotenzial bei Deinem Lösungsweg so sehe (XOR-Verknüpfungen), dann war ich wohl auf dem Holzweg ...

*) Habe inzwischen doch die Mühe auf mich genommen.
 
Zuletzt bearbeitet:
Zurück
Oben