# 64/32 Bit Division in AWL



## Lisa (28 Mai 2009)

Hallo ihr,

ich sitze gerade über einem S7-Programm (in AWL) und komme bei der Division nicht weiter:

Durch eine 32x32 Bit Multiplikation erhalte ich ein 64Bit Ergebnis, bestehend aus einem Low und einen High-Teil mit jeweils 32 Bit.
Dieses Ergebnis muss ich nun durch eine 32Bit Zahl dividieren.

Wie gehe ich bei der Division vor, der 64Bit große Dividend passt ja nicht in den 32 Bit Akku?

Könnt ihr mir da weiterhelfen?


----------



## Grubba (28 Mai 2009)

Das Ergebnis ist immer noch eine 32 Bit Zahl. Wenn das Ergebnis zu groß wird, bekommst Du das über ein bestimmtes Statusbit zurückgemeldet.


----------



## Lisa (28 Mai 2009)

Ja, das ist mir klar, aber nicht wie ich auf dieses 32 Bit Ergebnis komme.
Mein Problem ist die Division selbst.

Ich habe zuerst 2^31 geladen (da der Hi-Teil ja eigentlich 32 Stellen weiter links steht) und dies dann durch den Divisor geteilt (den Divisor habe ich vorher noch um 1 Stelle nach rechts geschoben, da der Hi-Teil ja 32 Stellen weiter links steht, und ich ja max 2^31 -1 laden kann). Anschließend habe ich den Low-Teil durch den Divisor geteilt und dann die Ergebnisse addiert.
So komme ich aber leider nur mit großer Abweichung an das richtige Ergebnis heran.

Wie kann ich die Division besser aufbauen, dass ich auch das richtige Ergebnis rausbekomme?


----------



## Grubba (28 Mai 2009)

?
Also erstmal der Reihe nach. Ich denke mal, Du sprichst von einer Ganzzahldivision?

Dann wäre der Ablauf z.B. folgender:

Teilung von 6.000.000 durch 1.500.000

L  L#6000000
L  L#1500000
/D                  -> hier steht jetzt im Akku 1 Dein Ergebnis
= MDxyz

In xyz stünde dann eine 4. Mehr nicht.


----------



## Lisa (28 Mai 2009)

Sorry, hab vergessen zu schreiben, dass es sich um eine Ganzzahldivision handelt.

Aber mein Dividend ist 64Bit groß, d.h. ich kann ihn nicht so laden wie in Deinem Beispiel die 6.000.000.
Ich habe also den Dividenden in zwei 32 Bit Zahlen unterteilt (High und Low- Teil)
Den Divisor kann ich ohne Probleme in den Akku laden.
Allerdings weiß ich jetzt nicht, wie ich mit dem unterteilten Dividenden rechnen soll.
Lade ich erst den High-Teil, teile diesen dann durch den Divisor und lade dann den Low-Teil und teile diesen ebenfalls durch den Divisor?
Oder wie muss ich da vorgehen?


----------



## Perfektionist (28 Mai 2009)

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.

```
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 ...


----------



## Grubba (28 Mai 2009)

Aha.

Das wird so ohne weiteres nicht so einfach machbar sein. Allerdings gibts da die freie Oscat-Bibliothek, in der auch Funktionen für 64Bit-Arithmetik enthalten sind. Hab ich aber noch nie benötigt. 

Wenn Dein Dividend nicht aus irgendeiner direkten Eingabe oder Konstanten entspringt, könntest Du Deinen Dividenden vorher künstlich "kleinhalten"

Also statt erst 5.000.000*5.000.000 und dann durch x 
zuerst 5.000.000 durch x und dann wieder *5.000.000.


----------



## Lisa (28 Mai 2009)

Ja, meine Multiplikation sieht genau so aus.
Da bekomm ich sogar richtige Ergebnisse raus.

Den Divisionsrest habe ich im 1. Versuch vernachlässigt, im 2. Versuch hab ich dann den Rest der Division (von High-Teil durch Divisor) zum Low-Teil des Dividenden dazuaddiert und dieses Ergebnis dann erst durch den Divisor geteilt.


----------



## Lisa (28 Mai 2009)

Leider funktioniert das mit dem künstlich kleinhalten nicht.
Zumindest weiß ich nicht wie.
Wenn ich nämlich zuerst dividiere und dann erst multipliziere, bekomme ich bei der Ganzzahldivision nur 0 oder 1 raus (1 auch nur wenn der Anwender den oberen Grenzwert eingibt, sonst immer nur 0).
Da ich leider nur Ganzzahldivision verwenden kann, würde ich dann fast immer mit 0 multiplizieren.


----------



## Grubba (28 Mai 2009)

Kannst Du die Festpunktwerte in Fließkommawerte wandeln, dann  dividieren/multiplizieren und dann im Bedarfsfall runden und wieder in Festpunkt zurückzuwandeln?


----------



## Lisa (28 Mai 2009)

Nein, ich darf leider nur mit ganzen Zahlen rechnen.
Real ist leider nicht erlaubt.


----------



## wolder (28 Mai 2009)

hört sich nach irgendsoein Lehrerscheiß an.
Ich würde das in eine Realzahl wandeln und dann damit rechnen.

Aber das darfst du ja nicht.

Poste doch mal konkrete Zahlen.
So richtig vorstellen kann ich mir das noch nicht.

Gruß wolder


----------



## Grubba (28 Mai 2009)

Ok, mal ein (einfaches) Beispiel. Dafür gehe ich davon aus, dass du nur mit 8Bit Werte rechnen kannst. Du sollt 64.020 durch 8 teilen.

Aufgeteilt in High und Low (hast Du ja schon gemacht)

kommt raus FA-14

Im HB=250 Dez, LB=20 Dez

250/8 = 31, Rest 2
20 /8 = 2, Rest 4

Dann kommt raus

Ergebnis = (31*256)+(2*256/8 )+ (2*1)
= 7936 + 64 +2
= 8002

Genauer gehts halt mit Festpunkt nicht.


----------



## Lisa (28 Mai 2009)

Die Formel die ich verwende lautet:

[(IN-b)*(c-d)] / (a-b) + d

(wobei für "IN" die Grenzwerte a bzw. b sind)

Beispiel:
IN: 10.000.000
a: 1.000
b: -10.000
c: 5.000.000
d: 100


Mit diesen Werten bekomme ich für den Dividenden [(IN-b)*(c-d)] :

2d84f0ce87c0

und für den Divisor (a-b):

2af8



Den Dividenden teile ich dann in den High-Teil: 2d84

und den Low-Teil: f0ce87c0


----------



## Lisa (28 Mai 2009)

Grubba schrieb:


> Ok, mal ein (einfaches) Beispiel. Dafür gehe ich davon aus, dass du nur mit 8Bit Werte rechnen kannst. Du sollt 64.020 durch 8 teilen.
> 
> Aufgeteilt in High und Low (hast Du ja schon gemacht)
> 
> ...


 


Stimm ich dir zu, allerdings hab ich dabei noch folgendes Problem:
Wenn der High-Teil kleiner ist, als der Divisor, bekommst Du ja 0 heraus.

Beispiel:
7FA

Im HB=7 Dez, LB=250 Dez

7/8 = 0, Rest 7
250/8 = 31, Rest 2

Somit würde ich ja für den High-Teil "0" als Ergebnis bekommen, obwohl die 7 theoretisch eine 700 wäre, wenn ich damit im Akku rechnen könnte.


----------



## Grubba (28 Mai 2009)

> Im HB=7 Dez, LB=250 Dez
> 
> 7/8 = 0, Rest 7
> 250/8 = 31, Rest 2


 
Ist doch nicht schlimm. Denk daran das der Rest auch noch mit 256 multipliziert werden muss....

(7*256 / 8 ) + 31 * 1 = (224) + 31 = 255. Besser gehts nicht.


----------



## Lisa (28 Mai 2009)

Grubba schrieb:


> Ist doch nicht schlimm. Denk daran das der Rest auch noch mit 256 multipliziert werden muss....
> 
> (7*256 / 8 ) + 31 * 1 = (224) + 31 = 255. Besser gehts nicht.


 

Gehe ich nun aber davon aus, dass mein Wert im High-Teil ziemlich groß ist, aber kleiner als der Divisor z.B.:

Dividend: FBFD (Dezimal: High: 251 Low: 253)
Divisor: FC (Dezimal: 252)


251/252 = 0   Rest 251
253/252 = 1   Rest 1


Dann müsste ich ja den Rest, also 251 mit 256 multiplizieren und dann durch 8 teilen.
Somit hätte ich dann wieder einen zu großen Wert, den ich nicht ohne Zerlegung durch 8 teilen kann, oder?


----------



## wolder (28 Mai 2009)

und für den Divisor (a-b):

2af8

Falsch. In deiner Formel fehlt noch +d

Raus kommt dezimal 11100 und nicht 11000.
Entsprechend 2B5C und nicht 2AF8.

Aber das ist das geringste Problem.

Wie hast du denn den Dividenden herausbekommen?!
Mit dem Calculator von Windoof?!
Mit der S7 hast du das bestimmt nicht geschafft. Die kann so große Zahlen nicht als Long bzw. Dint verarbeiten.
Und ja, du hast recht. Wenn du eine Kommazahl bei einer Division herausbekommst, dann wird die Zahl hinterm Komma gelöscht.

Aber du könntest das HB vorher mit 10 multiplizieren, bevor du es dividierst. Somit hättest du eine Kommastelle....

gruß wolder


----------



## Lisa (28 Mai 2009)

wolder schrieb:


> und für den Divisor (a-b):
> 
> 2af8
> 
> ...


 

Mir geht es momentan nur um die Division, die Addition von "d" erfolgt erst nach der Division, d ist also für die Division nicht relevant.

Den Dividenden habe ich rausbekommen, indem ich (IN-b) sowie (c-d)
jeweils in zwei 16 Bit Zahlen (Low und High- Teil) geteilt habe und dann die einzelnen Wörter miteinander multipliziert habe.
Anschließend habe ich die Ergebnisse der Multiplikation durch Addition zu zwei DINT -Zahlen (wiederrum Low und High) zusammengefügt.


----------



## Grubba (28 Mai 2009)

> Dividend: FBFD (Dezimal: High: 251 Low: 253)
> Divisor: FC (Dezimal: 252)
> 
> 
> ...


 
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.


----------



## Lisa (28 Mai 2009)

Grubba schrieb:


> Wo ist der Unterschied?
> 
> (251 * 256 / 252) + 1 = 254 +1 = 255 (Soll 255,9 )
> 
> ...


 


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?


----------



## wolder (28 Mai 2009)

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


----------



## Lisa (28 Mai 2009)

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




Perfektionist schrieb:


> 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.
> 
> ```
> z=x*y
> ...


----------



## Perfektionist (28 Mai 2009)

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):

```
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).


----------



## wolder (29 Mai 2009)

Danke Perfektionist!

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

Gruß wolder


----------



## Lisa (29 Mai 2009)

Perfektionist schrieb:


> 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".
> 
> 
> 
> ...


 



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.


----------



## Perfektionist (29 Mai 2009)

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


```
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:
	
	



```
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
```


----------



## Lisa (29 Mai 2009)

Perfektionist schrieb:


> 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


----------



## Lisa (18 Juni 2009)

Perfektionist schrieb:


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


 



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 10F32*1A08 *wäre, oder *D40* wenn 30*D40* 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


----------



## Perfektionist (18 Juni 2009)

also, da hab ich wohl zu schnell geschrieben:

```
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
	
	



```
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.


----------



## Lisa (18 Juni 2009)

Perfektionist schrieb:


> also, da hab ich wohl zu schnell geschrieben:
> 
> ```
> T_Divident_1 : WORD ;
> ...


 


Danke, danke, danke!!!
Jetzt funktionierts richtig!

Hatte total vergessen Quotient_0 und Quotient_1 auch auf DWORD zu ändern.

Aber kannst Du mir noch erklären, warum man ausgerechnet 80.000.000 laden muss, um das rotieren ins Ausgaberegister vorzubereiten?


Liebe Grüße
Lisa


----------



## Perfektionist (18 Juni 2009)

das sind 8000 0000 hex, also
1000 0000 0000 0000 0000 0000 0000 0000 bin.
damit wird das MSB gesetzt, das dann in das Anzeigebit reinrotiert wird.


----------



## Lisa (26 Juni 2009)

Hallo Perfektionist,
Deine Division funktioniert größtenteils wunderbar. Allerdings habe ich Probleme, wenn ich die Grenzwerte einsetze.
Meiner Meinung nach müsste es eigentlich auch mit diesen Werten noch funktionieren.

[(IN-b)*(c-d)] / (a-b) + d



Ich setze folgende Grenzwerte in die Formel ein:
IN: 2^30 -1 
a: 2^30 -1 
b: - 2^30 
c: 2^31 -1 
d: - 2^31 



Mit diesen Werten bekomme ich für den Dividenden [(IN-b)*(c-d)]: *7FFFFFFE80000001*


und für den Divisor (a-b): *7FFFFFFF*



Nun sollte ich als Ergebnis der Division *FFFFFFFF* rausbekommen, ich bekomme aber leider nur *0 *raus. Erst wenn ich meinen Divisor bis auf *67F3547 *verkleinere, erhalte ich wieder ein richtiges Ergebnis.


Kannst Du mir vielleicht erklären, warum das mit den Grenzwerten nicht funktioniert?


----------



## hovonlo (26 Juni 2009)

Ich habe jetzt nicht jedes Detail gelesen, aber bist du dir sicher da nicht in ein Vorzeichenproblem zu rutschen mit deinem d=-2^31? Falls irgendwo noch 32-Bit Arithmetik verwendet sollte, dann knallt es.


----------



## Lisa (26 Juni 2009)

hovonlo schrieb:


> Ich habe jetzt nicht jedes Detail gelesen, aber bist du dir sicher da nicht in ein Vorzeichenproblem zu rutschen mit deinem d=-2^31? Falls irgendwo noch 32-Bit Arithmetik verwendet sollte, dann knallt es.


 
Hallo,
glaube nicht, dass ich ein Vorzeichenproblem habe.
Bei der Differenz (c-d) reichen die 32 Bit nicht aus (zumindest nicht bei Grenzwerten). Deswegen habe ich das Ergebnis dieser Differenz auf einen Low-Teil (Word) und einen High-Teil (DINT) aufgeteilt. Somit habe ich 48Bit zur Verfügung und das muss eigentlich reichen.

Die Ergebnisse bis zur Division sind auch noch richtig, Dividend und Divisor werden richtig übergeben. Nur bei der Division gibt es dann irgendwie Probleme.


----------



## Larry Laffer (26 Juni 2009)

Lisa schrieb:


> ... Deswegen habe ich das Ergebnis dieser Differenz auf einen Low-Teil (Word) und einen High-Teil (DINT) aufgeteilt. Somit habe ich 48Bit zur Verfügung und das muss eigentlich reichen.
> 
> Die Ergebnisse bis zur Division sind auch noch richtig, Dividend und Divisor werden richtig übergeben. Nur bei der Division gibt es dann irgendwie Probleme.


 
Das ist genau das, was Hovonlo meinte ...
Der DINT wertet das Bit 2^31 als Vorzeichen aus. Das könnte das Problem sein. Ich würde also in dem DINT vermeiden, dieses Bit zu benutzen ...
Check das doch mal ...

Gruß
LL


----------



## hovonlo (26 Juni 2009)

Nachdem ja immer wieder Probleme auftauchen mit Zahlen >=31Bit hätte ich da ein paar Routinen zum Rechen mit 64 Bit Ganzzahlen

Es gibt Funktionen für:
- Multiplikation 32Bit * 32Bit vorzeichenlos mit 64 Bit Result
- Quadrat 32Bit vorzeichenlos mit 64 Bit Result
- Addition 64Bit + 64Bit vorzeichenbehaftet mit 64Bit Result
- Subtraktion 64Bit - 64Bit vorzeichenbehaftet mit 64Bit Result
- Multiplikation 64Bit * 64Bit vorzeichenbehaftet mit 128Bit Result
- Quadrat 64Bit vorzeichenbehaftet mit 128Bit Result (schneller als Multiplikation)
- Absolutwertbildung 64Bit
- Negierung 64Bit
- Division 64Bit / 64Bit vorzeichenbehaftet mit 64Bit Result und Rest

Das ganze ist selbst geschrieben und hat bisher funktioniert (Statistik-Anwendung mit Mittelwert & Standardabweichung)


----------



## BitMixer (19 Februar 2010)

*Danke an hovonlo*

Auch von mir ein *dickes Dankeschön*!!!


----------

