Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Seite 3 von 4 ErsteErste 1234 LetzteLetzte
Ergebnis 21 bis 30 von 38

Thema: 64/32 Bit Division in AWL

  1. #21
    Lisa ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    28.05.2009
    Beiträge
    18
    Danke
    9
    Erhielt 0 Danke für 0 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Zitat Zitat von Grubba Beitrag anzeigen
    Wo ist der Unterschied?

    (251 * 256 / 252) + 1 = 254 +1 = 255 (Soll 255,9 )

    Die Ungenauigkeit von 0.98 bekommst Du halt nicht weg. Da beißt die Maus keinen Faden ab. Es sei denn, Du prüfst das erste Ergebnis(251 * 256 / 252) auch noch mal auf den Rest ab. Dann kannst Du bei Bedarf auch noch ab oder aufrunden. Das Prinzip bleibt doch aber immer gleich. Natürlich musst Du aber Deine Dividierhäppchen so klein wählen, das sie nicht größer sind als die Hälfte Deines Rechenregisters. In Deinem Falle wären die Hälfte also 16 Bit.

    Es muss ja auf jeden Fall noch die Multiplikation von 2-8Bit Werten reinpassen.


    Danke, das habe ich bisher nicht bedacht.
    Dann reicht es also nicht, wenn ich meine 64 Bit in 2x32Bit aufteile, sondern ich muss die 32 Bit nochmal teilen?

  2. #22
    Registriert seit
    26.05.2009
    Beiträge
    541
    Danke
    35
    Erhielt 78 Danke für 69 Beiträge

    Standard

    Sorry,
    Ich hatte es so verstanden, dass b noch unter dem Bruchstrich steht.

    Poste mal dein Programm.

    Wenn du die beiden Subtraktionen in Wörtern ablegst (kein Problem) und diese dann multiplizierst, dann kommt doch eine größere Zahl raus als die SPS damit umgehen kann.

    also 5.000.000 * 5.000.000 = geht nicht!
    Die SPS kann diese Zahlen nicht multiplizieren.
    Ich raffs nicht!!!

    Gruß wolder

  3. #23
    Lisa ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    28.05.2009
    Beiträge
    18
    Danke
    9
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Hier ein Zitat von Perfektionist:
    Ich glaube er hat das mit der Multiplikation verständlicher erklärt.


    Zitat Zitat von Perfektionist Beitrag anzeigen
    Also, wenn ich recht verstanden habe, zweifelte Grubba ja an, dass Du einen Divident mit 64 Bit vorliegen hast. Ich gehe mal davon aus, dass Du die Multiplikation derart durchgeführt hast, dass Du die zwei 32-Bit-Zahlen zunächst von ihren Vorzeichen befreit hast, dann in jeweils zwei 16-Bit-Zahlen zerlegt hast und dann entsprechend vier mal multipliziert.
    Code:
    z=x*y
    x=65536a+b
    y=65536c+d
    z=(65536a+b)(65536c+d)
     =65536*65536ac+65536bc+65536ad+bd
    habe ich das mal soweit richtig erfasst?

    Bei Deiner Beschreibung der Division vermisse ich, wie Du mit dem Divisionsrest der ersten Division verfahren bist ...
    Geändert von Lisa (01.07.2009 um 13:09 Uhr)

  4. #24
    Registriert seit
    01.10.2007
    Ort
    Waiblingen
    Beiträge
    3.317
    Danke
    767
    Erhielt 536 Danke für 419 Beiträge

    Standard

    ja, ich denk auch schon die ganze Zeit nach, ob sich mit den 32-Bit-Registern der S7 elegant eine Division machen lässt, bei der der Divisor den Wertebereich einer Integer-Zahl übersteigt. Wäre der Divisor ein Integer (16Bit), so wäre es einfach, den Divident in vier Divisionsschritten "kleinzumachen".

    Was bleibt, ist, das ganze mit der Hand am Arm Bit für Bit durchzupopeln. um hier nicht unnötig lange das Prinzip zu erklären, möchte ich einfach ein auf 8/4-Bit verkürztes Beispiel darstellen (im Prinzip geht es so, wie in der Schule mit dem Dezimalsystem gelernt):
    Code:
    dividiere 45 durch 6 (das ist sieben Rest drei)
    00101101:0110=00000111
    00101101mod0110=0011
     
    0000 0010 1101     // Den Speicher für den Divident um die Länge des Divisors nach links erweitern
     
    0000 0101 1010    // und eins nach links schieben
    0110 --> geht 0-mal rein
     
    0000 1011 0100
    0110 --> 0-mal
     
    0001 0110 1000
    0110 --> 0-mal
     
    0010 1101 0000
    0110 --> 0-mal
     
    0101 1010 0000
    0110 --> 0-mal
     
    1011 0100 0000
    0110 --> 1-mal
     
    0101 0100 0000  // ist dann der Rest, der weiter zu dividieren ist
     
    1010 1000 0000  // und wieder weiter geschoben
    0110 --> geht einmal rein (also wieder 1 notieren)
     
    0100 1000 0000  // wieder der Rest davon
     
    1001 0000 0000
    0110 --> 1-mal
     
    0011 0000 0000  // nach achtmal Schieben steht hier nun Rest drei
     
     
    die mitgeschriebenen 0-mal bzw. 1-mal sind dann wie gewünscht: 0000 0111
    Das durchzuführen ist in AWL kein prinzipielles Problem. Mit dem Loopbefehl und den Rotierbefehlen , dem 32-Bit-Vergleich und 32-Bit-Subtraktion ist es möglich, den Code einigermassen überschaubar zu halten. Allerdings wird die Division auf diese Art und Weise merklich mehr Ausführungszeit als die 32-Bit-Multiplikation mit 64-Bit-Ergebnis benötigen (wundert es jemanden?). Aber das Ergebnis wird genau.

    Ich persönlich habe allerdings in einem vergleichbaren Fall mich damit begnügt, nur die ersten 32 signifikanten Bits der 64-Bit-Zahl durch die ersten signifikanten 16 Bit der 32-Bit-Zahl zu dividieren. klar - das Ergebnis ist entsprechend ungenauer und der Aufwand, sich die Zahlen zurechtzuschieben auch nicht zu verachten (irgendwie konnte ich das aufgrund vorgegebener Wertebereiche noch vereinfachen).

  5. Folgende 2 Benutzer sagen Danke zu Perfektionist für den nützlichen Beitrag:

    Lisa (29.05.2009),wolder (29.05.2009)

  6. #25
    Registriert seit
    26.05.2009
    Beiträge
    541
    Danke
    35
    Erhielt 78 Danke für 69 Beiträge

    Standard

    Danke Perfektionist!

    Wieder was dazu gelernt!!!
    MOD gibt mir den Rest heraus.

    Gruß wolder

  7. #26
    Lisa ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    28.05.2009
    Beiträge
    18
    Danke
    9
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Zitat Zitat von Perfektionist Beitrag anzeigen
    ja, ich denk auch schon die ganze Zeit nach, ob sich mit den 32-Bit-Registern der S7 elegant eine Division machen lässt, bei der der Divisor den Wertebereich einer Integer-Zahl übersteigt. Wäre der Divisor ein Integer (16Bit), so wäre es einfach, den Divident in vier Divisionsschritten "kleinzumachen".



    Das durchzuführen ist in AWL kein prinzipielles Problem. Mit dem Loopbefehl und den Rotierbefehlen , dem 32-Bit-Vergleich und 32-Bit-Subtraktion ist es möglich, den Code einigermassen überschaubar zu halten. Allerdings wird die Division auf diese Art und Weise merklich mehr Ausführungszeit als die 32-Bit-Multiplikation mit 64-Bit-Ergebnis benötigen (wundert es jemanden?). Aber das Ergebnis wird genau.

    Ich persönlich habe allerdings in einem vergleichbaren Fall mich damit begnügt, nur die ersten 32 signifikanten Bits der 64-Bit-Zahl durch die ersten signifikanten 16 Bit der 32-Bit-Zahl zu dividieren. klar - das Ergebnis ist entsprechend ungenauer und der Aufwand, sich die Zahlen zurechtzuschieben auch nicht zu verachten (irgendwie konnte ich das aufgrund vorgegebener Wertebereiche noch vereinfachen).



    Vielen Dank, das ist echt sehr hilfreich.
    Ich glaube allerdings nicht, dass ich mich auf die signifikanten Bit beschränken darf.
    Aber ich werde das auf jeden Fall mal so ausprobieren und mich dann nochmal melden.

  8. #27
    Registriert seit
    01.10.2007
    Ort
    Waiblingen
    Beiträge
    3.317
    Danke
    767
    Erhielt 536 Danke für 419 Beiträge

    Standard

    nun hab ich mal meine Mittagspause damit verbracht, so eine Division zu stricken - hier mal Code, aber ungetestet!

    Code:
    FUNCTION "div64-32" : VOID
    TITLE =
    VERSION : 0.1
     
    VAR_INPUT
      I_Divident_H : DWORD ; 
      I_Divident_L : DWORD ; 
      I_Divisor : DINT ; //negative Zahlen unzulässig
    END_VAR
    VAR_OUTPUT
      Q_Quotient_H : DWORD ; 
      Q_Quotient_L : DWORD ; 
      Q_Modulo : DWORD ; //oder auch "Rest"
    END_VAR
    VAR_TEMP
      T_Divident_2 : DINT ; 
      T_Divident_1 : WORD ; 
      T_Divident_0 : WORD ; 
      T_Quotient_1 : WORD ; 
      T_Quotient_0 : WORD ; 
      T_Schleifenzaehler : BYTE ; 
      T_Zwischenergebnis : BOOL ; 
    END_VAR
    BEGIN
    NETWORK
    TITLE =
          L     64; // Initialisierung
          T     #T_Schleifenzaehler; 
          L     0; 
          T     #T_Divident_2; 
          L     #I_Divident_H; 
          T     #T_Divident_1; 
          L     #I_Divident_L; 
          T     #T_Divident_0; 
    m001: NOP   0; // Schleifeneinsprungpunkt
          L     #T_Divident_0; // Dividentregister eins links schieben
          RLDA  ; 
          T     #T_Divident_0; 
          L     #T_Divident_1; 
          RLDA  ; 
          T     #T_Divident_1; 
          L     #T_Divident_2; 
          RLDA  ; 
          T     #T_Divident_2; 
          L     #I_Divisor; 
          <D    ; 
          R     #T_Zwischenergebnis; 
          SPB   m002; 
          =     #T_Zwischenergebnis; // wird hier auf 1 gesetzt
          -D    ; // und der Divident ...
          T     #T_Divident_2; // ... entsprechend vermindert
    m002: L     0; // Zwischenergebnis in das Ergebnisregister ...
          UN    #T_Zwischenergebnis; 
          SPB   m003; 
          L     DW#16#80000000; 
    m003: RLDA  ; // ... von rechts nach links reinschieben
          L     #T_Quotient_0; 
          RLDA  ; 
          T     #T_Quotient_0; 
          L     #T_Quotient_1; 
          RLDA  ; 
          T     #T_Quotient_1; 
          L     #T_Schleifenzaehler; // wiederholen
          L     1; 
          -I    ; 
          T     #T_Schleifenzaehler; 
          SPP   m001; 
          L     #T_Quotient_1; // Ergebnis ausgeben
          T     #Q_Quotient_H; 
          L     #T_Quotient_0; 
          T     #Q_Quotient_L; 
          L     #T_Divident_2; 
          T     #Q_Modulo; 
     
    END_FUNCTION
    und da ich die Darstellung / Formatierung im AWL-Editor schöner finde, hier nochmal nicht als Quelle, sondern aus dem Editor rauskopiert:
    Code:
          L     64                          // Initialisierung
          T     #T_Schleifenzaehler
          L     0
          T     #T_Divident_2
          L     #I_Divident_H
          T     #T_Divident_1
          L     #I_Divident_L
          T     #T_Divident_0
     
    m001: NOP   0                           // Schleifeneinsprungpunkt
     
          L     #T_Divident_0               // Dividentregister eins links schieben
          RLDA  
          T     #T_Divident_0
          L     #T_Divident_1
          RLDA  
          T     #T_Divident_1
          L     #T_Divident_2
          RLDA  
          T     #T_Divident_2
          L     #I_Divisor
          <D    
          R     #T_Zwischenergebnis
          SPB   m002
          =     #T_Zwischenergebnis         // wird hier auf 1 gesetzt
          -D                                // und der Divident ...
          T     #T_Divident_2               // ... entsprechend vermindert
     
    m002: L     0                           // Zwischenergebnis in das Ergebnisregister ...
          UN    #T_Zwischenergebnis
          SPB   m003
          L     DW#16#80000000
    m003: RLDA                              // ... von rechts nach links reinschieben
          L     #T_Quotient_0
          RLDA  
          T     #T_Quotient_0
          L     #T_Quotient_1
          RLDA  
          T     #T_Quotient_1
     
          L     #T_Schleifenzaehler         // wiederholen
          L     1
          -I    
          T     #T_Schleifenzaehler
          SPP   m001
     
          L     #T_Quotient_1               // Ergebnis ausgeben
          T     #Q_Quotient_H
          L     #T_Quotient_0
          T     #Q_Quotient_L
          L     #T_Divident_2
          T     #Q_Modulo
    Geändert von Perfektionist (29.05.2009 um 12:43 Uhr)

  9. Folgender Benutzer sagt Danke zu Perfektionist für den nützlichen Beitrag:

    Lisa (29.05.2009)

  10. #28
    Lisa ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    28.05.2009
    Beiträge
    18
    Danke
    9
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Zitat Zitat von Perfektionist Beitrag anzeigen
    nun hab ich mal meine Mittagspause damit verbracht, so eine Division zu stricken - hier mal Code, aber ungetestet!


    Vielen vielen Dank!
    Hab bis gerade versuch das ganze selbst zu entwerfen (allerdings bisher nur mit 32 Schleifendurchläufen), bis ich Deine Nachricht entdeckt hab.
    Muss jetzt aber leider heim, in 45min is Abfahrt in Urlaub.
    Habe ab jetzt bis 16.6 "Zwangsurlaub" und dann werde ich Dein Programm testen! Daheim kann ich es leider nicht ausprobieren.

    Also vielen Dank nochmal und ich melde mich dann, wenn ich wieder in der Arbeit bin und das Programm getestet hab.

    Liebe Grüße
    Lisa

  11. #29
    Lisa ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    28.05.2009
    Beiträge
    18
    Danke
    9
    Erhielt 0 Danke für 0 Beiträge

    Standard

    Zitat Zitat von Perfektionist Beitrag anzeigen
    nun hab ich mal meine Mittagspause damit verbracht, so eine Division zu stricken - hier mal Code, aber ungetestet!

    Code:
          L     64                          // Initialisierung
          T     #T_Schleifenzaehler
          L     0
          T     #T_Divident_2
          L     #I_Divident_H
          T     #T_Divident_1
          L     #I_Divident_L
          T     #T_Divident_0
     
    m001: NOP   0                           // Schleifeneinsprungpunkt
     
          L     #T_Divident_0               // Dividentregister eins links schieben
          RLDA  
          T     #T_Divident_0
          L     #T_Divident_1
          RLDA  
          T     #T_Divident_1
          L     #T_Divident_2
          RLDA  
          T     #T_Divident_2
          L     #I_Divisor
          <D    
          R     #T_Zwischenergebnis
          SPB   m002
          =     #T_Zwischenergebnis         // wird hier auf 1 gesetzt
          -D                                // und der Divident ...
          T     #T_Divident_2               // ... entsprechend vermindert
     
    m002: L     0                           // Zwischenergebnis in das Ergebnisregister ...
          UN    #T_Zwischenergebnis
          SPB   m003
          L     DW#16#80000000
    m003: RLDA                              // ... von rechts nach links reinschieben
          L     #T_Quotient_0
          RLDA  
          T     #T_Quotient_0
          L     #T_Quotient_1
          RLDA  
          T     #T_Quotient_1
     
          L     #T_Schleifenzaehler         // wiederholen
          L     1
          -I    
          T     #T_Schleifenzaehler
          SPP   m001
     
          L     #T_Quotient_1               // Ergebnis ausgeben
          T     #Q_Quotient_H
          L     #T_Quotient_0
          T     #Q_Quotient_L
          L     #T_Divident_2
          T     #Q_Modulo



    Hallo Perfektionist,

    ich hätte noch ein paar Fragen zu Deinem Code:
    Warum ist der Befehl "L DW#16#80000000" in m002 nötig?
    Geht es hier nur darum, dass eine 1 nach links rotiert wird oder hat das einen anderen Grund?
    Und warum sind folgende 2 Variablen nur WORD und nicht DWORD?
    T_Divident_1 : WORD ;
    T_Divident_0 : WORD ;

    Ich habe vorhin das Programm getestet.
    Für T_Divident_1 und T_Divident_0 habe ich DWORD statt WORD genommen, weil sonst nur 0 rauskam.
    Nach dieser Änderung bekomme ich das Low-WORD richtig heraus, der Rest ist aber falsch.
    Zum Beispiel erhalte ich 1A08, wenn das richtige Ergebnis 10F321A08 wäre, oder D40 wenn 30D40 richtig wäre.


    Für die Berechnung habe ich den Low-Teil des 64 Bit Dividenden der Variablen "T_Divident_0" und den Hi-Teil der Variablen "T_Divident_1" zugewiesen.
    Ja und den Divisor hab ich I_Divisor zugeordnet.

    L 64 // Initialisierung
    T #T_Schleifenzaehler

    L 0
    T #T_Divident_2

    // L #I_Divident_H
    L #erg_mul_HI // HI-Teil des Dividenden
    T #T_Divident_1

    // L #I_Divident_L
    L #erg_mul_LO // LO-Teil des Dividenden
    T #T_Divident_0

    L #divisor
    T #I_Divisor


    Kannst du mir bitte nochmal helfen, warum das noch nicht richtig funktioniert?

    Danke schonmal

    Lisa

  12. #30
    Registriert seit
    01.10.2007
    Ort
    Waiblingen
    Beiträge
    3.317
    Danke
    767
    Erhielt 536 Danke für 419 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    also, da hab ich wohl zu schnell geschrieben:
    Code:
      T_Divident_1 : WORD ; 
      T_Divident_0 : WORD ; 
      T_Quotient_1 : WORD ; 
      T_Quotient_0 : WORD ;
    das muss nicht nur zweimal, wie Du bereits richtig erkannt hast, sondern sogar viermal DWORD sein.

    mit
    Code:
          UN    #T_Zwischenergebnis
          SPB   m003
          L     DW#16#80000000
    m003: RLDA                              // ... von rechts nach links reinschieben
    wird das reinrotieren des Ergebnisbit in das Ausgaberegister vorbereitet.

  13. Folgender Benutzer sagt Danke zu Perfektionist für den nützlichen Beitrag:

    Lisa (18.06.2009)

Ähnliche Themen

  1. SCL Division mit Rest
    Von vollmi im Forum Simatic
    Antworten: 5
    Letzter Beitrag: 05.06.2009, 15:41
  2. Division von INT Zahlen
    Von HonestAnnie im Forum Simatic
    Antworten: 58
    Letzter Beitrag: 16.07.2008, 23:31
  3. Division von DInt
    Von godi im Forum Simatic
    Antworten: 1
    Letzter Beitrag: 07.01.2006, 08:10
  4. Genauest mögliche Division zweier Zahlen
    Von Anonymous im Forum Simatic
    Antworten: 3
    Letzter Beitrag: 16.04.2005, 09:53
  5. Division durch null
    Von kpeter im Forum Simatic
    Antworten: 5
    Letzter Beitrag: 08.02.2005, 18:48

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •