64/32 Bit Division in AWL

Lisa

Level-1
Beiträge
18
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
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?
 
Das Ergebnis ist immer noch eine 32 Bit Zahl. Wenn das Ergebnis zu groß wird, bekommst Du das über ein bestimmtes Statusbit zurückgemeldet.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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?
 
?
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.
 
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?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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 ...
 
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.
 
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.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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.
 
Kannst Du die Festpunktwerte in Fließkommawerte wandeln, dann dividieren/multiplizieren und dann im Bedarfsfall runden und wieder in Festpunkt zurückzuwandeln?
 
Nein, ich darf leider nur mit ganzen Zahlen rechnen.
Real ist leider nicht erlaubt.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
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
 
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.
 
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
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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.



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.
 
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.
 
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?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
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
 
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


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.
 
Dividend: FBFD (Dezimal: High: 251 Low: 253)
Divisor: FC (Dezimal: 252)


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

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.
 
Zurück
Oben