Konvertierung Integer (3-stellig) in einzelne CHAR

HarryH

Level-1
Beiträge
142
Reaktionspunkte
4
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich habe ein Integer welche max. den Wert 999 erreichen kann -> Also max. 3-stellig. Alle drei Stellen muss ich in je ein CHAR umwandeln. Beispiel:

#NR_Integer = 123 --> konvertieren nach -->
#Nr_Hunderter_char = '1'
#Nr_Zehner_char = '2'
#Nr_Einer_char = '3'

Ich habe das wie folgt gelöst, es erscheint mir aber irgendwie sehr umständlich. Hat jemand eine elegantere Möglichkeit?

Code:
// Nummer Hunderter konvertieren
      L     #NR_Integer
      ITD   
      DTR   
      L     1.000000e+002
      /R    
      TRUNC 
      T     #Nr_Hunderter_int               // Zwischenspeicher
      L     48
      +I    
      T     #Nr_Hunderter_char



// Nummer Zehner konvertieren
      L     #Nr_Hunderter_int
      L     100
      *I    
      L     #NR_Integer
      TAK   
      -I    
      ITD   
      DTR   
      L     1.000000e+001
      /R    
      TRUNC 
      T     #Nr_Zehner_int              // Zwischenspeicher
      L     48
      +I    
      T     #Nr_Zehner_char




// Nummer Einer konvertieren
      L     #NR_Integer
      L     10
      MOD   
      T     #Nr_Einer_int              // Zwischenspeicher
      L     48
      +I    
      T     #Nr_Einer_char
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Mein FC der das tut sieht so aus:

Code:
//backup
      L     DBNO
      T     #backup_DB
      TAR1  
      T     #backup_AR1

//Initialisieren
      L     #DINTVAL
      T     #ZAHL

//Pointer auf Ascii laden
      L     P##ASCII
      LAR1  

//Schleife mit Länge des Pointers initialisieren
      L     W [AR1,P#2.0]
      T     #SCHLEIFE_MAX

//Datentyp ermitteln, nur Byte gültig!
//      L     B [AR1,P#1.0]
// 4 - 5 -->  Länge 2
// 6 - 8 -->  Länge 4

//DB des Pointers öffnen (falls vorhanden!)
      L     0
      L     W [AR1,P#4.0]
      ==I   
      SPB   spOK
      T     #DB_NR
      AUF   DB [#DB_NR]

//Wenn Speicherbereich DI, in DB ändern
      L     B [AR1,P#6.0]
      L     B#16#85                     //Speicerbereich DI??
      ==I   
      SPBN  spOK
      L     B#16#84                     //Speicherberich DB
      T     B [AR1,P#6.0]

//Startadresse in AR1 laden
spOK: L     D [AR1,P#6.0]
      LAR1  

//Potenzfaktor Startwert
      L     L#1
      T     #FAKTOR

//max Potenzfaktor bestimmen (10^(LängeAny-1), ausser wenn Schleife_max = 1, da loop sonst ins negative dekrementiert!
      L     0
      L     #SCHLEIFE_MAX
      +     -1
      ==I   
      SPB   sl2

sl1:  T     #SCHLEIFE
      L     L#10
      L     #FAKTOR
      *D    
      T     #FAKTOR
      L     #SCHLEIFE
      LOOP  sl1

//Zahl zu groß, ergebniss = 0
      L     #FAKTOR
      L     10
      *D    
      L     #ZAHL
      >D    
      SPB   sl2
      L     0
      T     #ZAHL

//Aktuelles Zeichen laden und prüfen ob Ziffer
sl2:  L     #ZAHL
      L     #FAKTOR
      /D    
      T     B [AR1,P#0.0]               //Ziffer in DB eintragen
      L     #FAKTOR
      *D    
      NEGD  
      L     #ZAHL
      +D    
      T     #ZAHL

//Ziffer in ascii wandeln...
      L     B [AR1,P#0.0]
      L     '0'
      +I    
      T     B [AR1,P#0.0]

      L     1
      L     #FAKTOR
      ==D   
      SPB   ende

      L     L#10
      /D    
      T     #FAKTOR

      L     P#1.0
      +AR1  
      SPA   sl2

ende: AUF   DB [#backup_DB]
      L     #backup_AR1
      LAR1

Wobei In DINTVAL ein DINT mit der Zahl ist und ASCII ein ANY of das Char Array. Kann beliebig große Dints in Ascii wandeln (die länge wird aus dem ANY ermittelt!)

Da gibts bestimmt noch optimierungen in meinem FC aber er geht!
 
Das hier ist meiner:
Code:
      L     #INT_Wert                   // Eingangswert prüfen
      L     0
      >=I                               // auf größer oder gleich 0
      POP                               // und wieder in AKKU1 holen.
      SPB   ING0                        // Wenn >=0 überspringen,
      NEGI                              // ansonsten negieren, damit >=0.
ING0: NOP   0
      L     10                          // Durch 10 teilen.
      /I    
      TAD                               // Reihenfolge der Bytes in AKKU1
//                                      // tauschen damit der Divisionsrest
//                                      // in AKKU1 LL und LH liegt.
      TAW                               // Bytes in AKKU1-L tauschen
//                                      // damit der Divisionsrest in die
//                                      // richtige Reihenfolge kommt.
      INC   48                          // + 48 ergibt den ASCII-Code
      T     #Einer                      // der Einerstelle.
      TAD                               // Reihenfolge der Bytes in AKKU1
//                                      // tauschen damit das Divisions-
//                                      // ergebnis wieder in AKKU1-L liegt.
      L     10                          // Und so weiter...
      /I    
      TAD   
      TAW   
      INC   48
      T     #Zehner
      TAD   
      L     10
      /I    
      TAD   
      TAW   
      INC   48
      T     #Hunderter
      TAD   
      L     10
      /I    
      TAD   
      TAW   
      INC   48
      T     #Tausender
 
Hallo,
man könnte die Zahl auch mit einer der (Siemens-)Konvertierungs-Funktionen (INT_to_String oder DINT_to_String) in einen String wandeln, auf den dann einen Pointer bilden und die beinhalteten Zeichen (die dann ja schon vom Fromat Char sind) einfach herauslesen ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Siehe auch das folgende Programmbeispiel:

Code:
UNCTION FC 100 : VOID
TITLE =Konvertierung INT Nummer in CHAR Nummer
//INT  Nummer                 = 000...999
//
//CHAR Nummer Hunderterstelle = '0'...'9'
//CHAR Nummer Zehnerstelle    = '0'...'9'
//CHAR Nummer Einerstelle     = '0'...'9'
//   
AUTHOR : Kai
FAMILY : SPSForum
NAME : '45971'
VERSION : 1.0
 
VAR_INPUT
  INT_Nummer : INT ; //INT Nummer
END_VAR
VAR_OUTPUT
  CHAR_Hunderterstelle : CHAR ; //CHAR Nummer Hunderterstelle
  CHAR_Zehnerstelle : CHAR ; //CHAR Nummer Zehnerstelle
  CHAR_Einerstelle : CHAR ; //CHAR Nummer Einerstelle
END_VAR
BEGIN
NETWORK
TITLE =
      L     #INT_Nummer; // INT Nummer
      ITB   ; 
      SLW   4; 
      SRW   12; 
      L     48; 
      +I    ; 
      T     #CHAR_Hunderterstelle; // CHAR Nummer Hunderterstelle
 
      L     #INT_Nummer; // INT Nummer
      ITB   ; 
      SLW   8; 
      SRW   12; 
      L     48; 
      +I    ; 
      T     #CHAR_Zehnerstelle; // CHAR Nummer Zehnerstelle
 
      L     #INT_Nummer; // INT Nummer
      ITB   ; 
      SLW   12; 
      SRW   12; 
      L     48; 
      +I    ; 
      T     #CHAR_Einerstelle; // CHAR Nummer Einerstelle
END_FUNCTION

Gruß Kai
 

Anhänge

  • OB1.pdf
    6,3 KB · Aufrufe: 8
  • FC100.pdf
    5,8 KB · Aufrufe: 13
  • PLCSIM.jpg
    PLCSIM.jpg
    162,7 KB · Aufrufe: 20
  • 45971.zip
    30,2 KB · Aufrufe: 7
Nibble-Spiel

... und das hier ist meiner:
Code:
      L     #INT_Wert           // darf max 999 sein, Vorzeichen wird ignoriert
      ITB                       // 0000_0000_0000_0000|VVVV_HHHH_ZZZZ_EEEE
      PUSH                      // 0000_0000_0000_0000|VVVV_HHHH_ZZZZ_EEEE
      UW    W#16#F0             // 0000_0000_0000_0000|0000_0000_ZZZZ_0000
      RRD   12                  // 0000_ZZZZ_0000_0000|0000_0000_0000_0000
      TAK                       // 0000_0000_0000_0000|VVVV_HHHH_ZZZZ_EEEE
      UW    W#16#F0F            // 0000_0000_0000_0000|0000_HHHH_0000_EEEE
      OD                        // 0000_ZZZZ_0000_0000|0000_HHHH_0000_EEEE
      OD    DW#16#30303030      // 0011_ZZZZ_0011_0000|0011_HHHH_0011_EEEE
      T     #Einer
      TAW                       // 0011_ZZZZ_0011_0000|0011_EEEE_0011_HHHH
      T     #Hunderter
      TAD                       // 0011_HHHH_0011_EEEE|0011_0000_0011_ZZZZ
      T     #Zehner

Harald
 
@Harald
Der dürfte schwer zu toppen sein.
Den hast Du Dir aber nicht spontan aus dem Ärmel geschüttelt, oder?!
 
Den hast Du Dir aber nicht spontan aus dem Ärmel geschüttelt, oder?!
Nee, spontan war zunächst diese Variante:
Code:
      L     #INT_Wert           // darf max 999 sein, Vorzeichen wird ignoriert
      ITB                       // 0000_0000_0000_0000|VVVV_HHHH_ZZZZ_EEEE
      PUSH                      // 0000_0000_0000_0000|VVVV_HHHH_ZZZZ_EEEE
      UW    W#16#FF0            // 0000_0000_0000_0000|0000_HHHH_ZZZZ_0000
      SLD   8                   // 0000_0000_0000_HHHH|ZZZZ_0000_0000_0000   
      SRW   4                   // 0000_0000_0000_HHHH|0000_ZZZZ_0000_0000
      TAK                       // 0000_0000_0000_0000|VVVV_HHHH_ZZZZ_EEEE
      UW    W#16#F              // 0000_0000_0000_0000|0000_0000_0000_EEEE
      OD                        // 0000_0000_0000_HHHH|0000_ZZZZ_0000_EEEE
      OD    DW#16#303030        // 0000_0000_0011_HHHH|0011_ZZZZ_0011_EEEE
      T     #Einer
      TAW                       // 0000_0000_0011_HHHH|0011_EEEE_0011_ZZZZ
      T     #Zehner
      TAD                       // 0001_ZZZZ_0011_EEEE|0011_HHHH_0000_0000
      TAW                       // 0001_ZZZZ_0011_EEEE|0000_0000_0011_HHHH
      T     #Hunderter
Für die kürzere Variante in #7 mußte ich schon etwas länger nachdenken ...

Harald
 
Respekt Männers.

Sowas nenne ich Brainstorming.

Echt gute Lösungen! Da freut sich Harry bestimmt.

:sc5:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wir sollten hier im Forum einen kleinen Wettbewerb starten:
Jede Woche eine kleine Programmieraufgabe (von Art und Umfang ungefähr so, wie diese hier) und Gewinner ist, wer nach x Tagen die wenigsten Codezeilen für die Aufgabe benötigt.
Zu gewinnen gibt's Ruhm und Ehre!
 
Eine Zeile ging noch: ;)
Richtig, wenn man die Zehnerziffer gleich wegspeichert, dann geht es tatsächlich noch etwas kürzer.
Ausgehend vom Algorithmus zur Umwandlung einer BCD-Zahl in einen STRING bzw. CHAR-Array habe ich übersehen, daß ich ja nur die Einzelziffern in beliebiger Reihenfolge herauslösen muß statt eine Gesamt-Bytefolge zu erzeugen. War wohl schon zu spät zum perfekt-sein in der letzten Nacht. ;)

Jetzt fällt mir auch wieder die Reinform des Standard-BCD-Zerlegungsalgorithmus ein:
Code:
      L     #DINT_Wert          // -9.999.999 ... 9.999.999
      DTB                       // vvvv_mmmm_hhhh_zzzz|TTTT_HHHH_ZZZZ_EEEE
      PUSH                      // vvvv_mmmm_hhhh_zzzz|TTTT_HHHH_ZZZZ_EEEE

      UD    DW#16#F0F0F0F       // 0000_mmmm_0000_zzzz|0000_HHHH_0000_EEEE
      OD    DW#16#30303030      // 0011_mmmm_0011_zzzz|0011_HHHH_0011_EEEE
      T     #Einer
      SRD   8                   // 0000_0000_0011_mmmm|0011_zzzz|0011_HHHH
      T     #Hunderter
      SRD   8                   // 0000_0000_0000_0000|0011_mmmm_0011_zzzz
      T     #Zehntausender
      SRD   8                   // 0000_0000_0000_0000|0000_0000_0011_mmmm
      T     #Millioner

      POP                       // vvvv_mmmm_hhhh_zzzz|TTTT_HHHH_ZZZZ_EEEE
      SRD   4                   // 0000_vvvv_mmmm_hhhh|zzzz_TTTT_HHHH_ZZZZ
      UD    DW#16#D0F0F0F       // 0000_vv0v_0000_hhhh|0000_TTTT_0000_ZZZZ
      OD    DW#16#20303030      // 0010_vv0v_0011_hhhh|0011_TTTT_0011_ZZZZ
      T     #Zehner
      SRD   8                   // 0000_0000_0010_vv0v|0011_hhhh_0011_TTTT
      T     #Tausender
      SRD   8                   // 0000_0000_0000_0000|0010_vv0v_0011_hhhh
      T     #Hunderttausender
      SRD   8                   // 0000_0000_0000_0000|0000_0000_0010_vv0v
      T     #Vorzeichen         // '-' oder Leerzeichen ' '

Harald
 
Wir sollten hier im Forum einen kleinen Wettbewerb starten:
Jede Woche eine kleine Programmieraufgabe (von Art und Umfang ungefähr so, wie diese hier)
Hatte ich auch schon mal überlegt, doch wer findet regelmäßig eine geeignete Aufgabenstellung, deren clevere Lösung noch nicht hier im Forum zu finden ist?
Daß offenbar einige Programmierer in der Lösung solcher Aufgaben wie eben mit Standard-Algorithmen ein Problem haben, hätte ich nicht gedacht.

Zu gewinnen gibt's Ruhm und Ehre!
Ein Danke vom Fragesteller/Themenstarter tut's auch schon ... :ROFLMAO:

Harald
 
Jetzt fällt mir auch wieder die Reinform des Standard-BCD-Zerlegungsalgorithmus ein:
Code:
      L     #DINT_Wert          // -9.999.999 ... 9.999.999
      DTB                       // vvvv_mmmm_hhhh_zzzz|TTTT_HHHH_ZZZZ_EEEE
      PUSH                      // vvvv_mmmm_hhhh_zzzz|TTTT_HHHH_ZZZZ_EEEE

      UD    DW#16#F0F0F0F       // 0000_mmmm_0000_zzzz|0000_HHHH_0000_EEEE
      OD    DW#16#30303030      // 0011_mmmm_0011_zzzz|0011_HHHH_0011_EEEE
      T     #Einer
      SRD   8                   // 0000_0000_0011_mmmm|0011_zzzz|0011_HHHH
      T     #Hunderter
      SRD   8                   // 0000_0000_0000_0000|0011_mmmm_0011_zzzz
      T     #Zehntausender
      SRD   8                   // 0000_0000_0000_0000|0000_0000_0011_mmmm
      T     #Millioner

      POP                       // vvvv_mmmm_hhhh_zzzz|TTTT_HHHH_ZZZZ_EEEE
      SRD   4                   // 0000_vvvv_mmmm_hhhh|zzzz_TTTT_HHHH_ZZZZ
      UD    DW#16#D0F0F0F       // 0000_vv0v_0000_hhhh|0000_TTTT_0000_ZZZZ
      OD    DW#16#20303030      // 0010_vv0v_0011_hhhh|0011_TTTT_0011_ZZZZ
      T     #Zehner
      SRD   8                   // 0000_0000_0010_vv0v|0011_hhhh_0011_TTTT
      T     #Tausender
      SRD   8                   // 0000_0000_0000_0000|0010_vv0v_0011_hhhh
      T     #Hunderttausender
      SRD   8                   // 0000_0000_0000_0000|0000_0000_0010_vv0v
      T     #Vorzeichen         // '-' oder Leerzeichen ' '
Harald

Hallo Harald,
ich bin grad am überlegen, ob dies wirklich bei negativen Zahlen klappt.
Die sind doch im Zweierkomplement.

Ansonsten genial logisch :s1:

Gruß Roland
 
Zurück
Oben