Forum: Mikrocontroller und Digitale Elektronik Rechnen mit Integern


von uC-Anfänger (Gast)


Lesenswert?

Hallo, ich hab ein Problem bei berechnungen an einem C166.
Am besten zeige ich euch das Problem an einem Beispiel auf:
Ich will die Kennlinie einer Solarzelle berechnen lassen, habe jedoch
im C166 keine Gleitkommaoperationen zur Verwendung.
Jetzt benötige ich aber einige Hilfswerte, um die Kennlinie zu 
berechnen.
Folgende Werte habe ich als Parameter:
a = 14221
b = 7389
c = 11403
d = 6898

Nun benötige ich zur berechnung folgende Formel:
M = (a/b)*(-5,411*((d*c)/(b*a))+6,450*(c/a)+3,417*(d/b)-4,422)

das Problem bei der Sache ist, dass durch die Division von z.b. a/b so 
kleine Werte entstehen, welche ohne Nachkommastellen unbrauchbar sind.

Weiss jemand eine lösung für dieses Problem?
ich muss mit den berechneten Werten danach auch noch weitere Berechnung 
durchführen können.

Danke schon mal für eure Hilfe!!!!

von Karl H. (kbuchegg)


Lesenswert?

uC-Anfänger wrote:

> Weiss jemand eine lösung für dieses Problem?

* Die Formel umwandeln. Bring den ganzen Wust zunächst
  mal auf 1 Bruch. Dann hast du nur Zähler und Nenner und
  1 Division.

* Fix Punkt Arithmetik.
  Nimm zumindest mal alle Werte mal 1000.
  Dadurch fallen in deiner Formel schon mal alle
  Kommastellen weg, weil alle Zahlen ganzzahlig werden.

  Du musst aber untersuchen ob dann in deiner Berechnung
  alle Zwischenergebnisse im erlaubten Bereich bleiben oder
  ob es Overflows gibt. Da ist ein bischen experimentieren
  angesagt.

von Matthias (Gast)


Lesenswert?

Ja, Divisionen zuletzt durchführen.
Und solche Zahlen wie -5,411 auf ganze aufrunden.
zB auf -5541/1024.
Also ich meine, multipliziere die ganze! Gleichung mit zB 1024:


1024*M = 1024 
[(a/b)*(-5,411*((d*c)/(b*a))+6,450*(c/a)+3,417*(d/b)-4,422)]
jetzt das reinrechnen:

           a           c * d         c          d
1024*M = ----- (-5541)------- + 6605---- + 3499--- - 4528
           b           b * a         a          b
          ^^^^^^^^^^^^^^^^^^^ (kürzt sich das a raus, aber kann ja mal 
bleiben)

am besten jetzt den zweiten und dritten term auf a*b^2 als HN erweitern:

            (-5541)*a*c*d + 6605*b^2*c + 3499*a*b*d - 4528*a*b^2
1024*M = ----------------------------------------------------------
                          a*b^2

Jetzt die 1024 durch "Schieben des Ergebnisses um 10bit nach rechts" 
herausrechnen....
Hast allerdings bei dieser Rechnung größere Datentypen als int (16bit). 
Da musst du aufpassen und nachsehen, welchen du brauchst, dass es nicht 
zum überlauf kommt...


PS: gibt sicherlich noch andere geeignete erweiterungen der gleichung...

von uC-Anfänger (Gast)


Lesenswert?

Danke für eure Tips, da bin ich wohl grad ein wenig aufm Schlauch 
gestanden, auf das auflösen hätt ich auch kommen können.
Werd das gleich mal testen!!!

von uC-Anfänger (Gast)


Lesenswert?

Hab das ganze jetzt mal nachgerechnet, ab er leider gibt es hier keinen 
Datentypen, mit dem ich so große Zahlen berechnen kann (a*b*d) ohne 
einen Overflow zu bekommen.

von Matthias (Gast)


Lesenswert?

Ja, jede Zahl ist 16bit. ALso brauchst du 24bit mindestens.
Ich glaube, es gibt ein uint32_t.
Den kannst du nehmen, da passt viel rein ;-)

von Johannes M. (johnny-m)


Lesenswert?

16Bit*16Bit*16Bit = 48 Bit => unsigned long long (64 Bit) als 
nächstgrößerer Datentyp.

von Willi W. (williwacker)


Lesenswert?

Alternative: Dein Problem scheint nun nicht allzu zeitkritisch zu sein: 
Nimm einen C-Compiler der floats (doubles) unterstützt und Du kommst 
recht leicht ans Ziel, weil Dir der Compiler den ganzen "Heckmeck" 
(siehe oben) abnimmt.

Dennoch ist es gut, die oben beschriebenen Probleme zu kennen.

Ciao

von Matthias (Gast)


Lesenswert?

@ Johannes M.:

äh, ja.. da hat mich wohl mein rechenbrett irgendwie ausgetrickst...

von uC-Anfänger (Gast)


Lesenswert?

Hallo Willi,
kann leider keinen anderen Compiler benutzen, da meine Programm nur ein 
kleiner Teil einer Software ist, welche auf einem Umrichter läuft. Bin 
also an meinen Compiler gebunden.
Ein weiteres Problem ist, dass in dieser Software keine Datentypen mit 
64bit vorgesehen sind.
Gibts da noch andere Lösungen, bei denen ich mit 32 Bit auskomme?

von Karl H. (kbuchegg)


Lesenswert?

uC-Anfänger wrote:
> Hab das ganze jetzt mal nachgerechnet, ab er leider gibt es hier keinen
> Datentypen, mit dem ich so große Zahlen berechnen kann (a*b*d) ohne
> einen Overflow zu bekommen.

Welches ist der größte Datentyp den du zur Verfügung hast?
(Anzahl Bit)

Wie sehen die Wertebereiche für a, b, c, d aus? Eventuell
bleiben da ein paar ungenutzte Bits übrig, die die Anforderungen
an den Datentyp etwas senken können.

Ansonsten bleibt nur noch: mit der Gleichung spielen.

zb. könnte man im Zähler mal das a herausheben

           a( 3499*b*d - 5541*c*d - 4528*b^2 ) + 6605*b^2*c
1024*M = ---------------------------------------------------
                          a*b^2

schweren Herzens auf 2 Brüche aufteilen

           a( 3499*b*d - 5541*c*d - 4528*b^2 )    6605*b^2*c
1024*M = ------------------------------------- + ------------
                          a*b^2                      a*b^2

und kürzen

           3499*b*d - 5541*c*d - 4528*b^2    6605*c
1024*M = -------------------------------- + --------
                       b^2                      a

das muesste jetzt die Anforderungen an deine Datentypen
etwas gesenkt haben.

Wenn das immer noch nicht reicht: Im ersten Bruch
würde noch was gehen, indem man aufteilt und b heraushebt.



von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger wrote:

>            3499*b*d - 5541*c*d - 4528*b^2    6605*c
> 1024*M = -------------------------------- + --------
>                        b^2                      a
>
> Wenn das immer noch nicht reicht: Im ersten Bruch
> würde noch was gehen, indem man aufteilt und b heraushebt.

Nein QUatsch. Das bringt nichts, weil dann

     - 5541  c  d
    ----------------
          b^2

übrigbleibt und da geht nichts mehr.

Aber vielleicht reichts mit den Wertebereichen für a, b, c, d
auch so schon.

von uC-Anfänger (Gast)


Lesenswert?

Der größte datentyp, den ich zur Verfügung habe ist 32 Bit. Kann hier 
jedoch keine unsigned verwenden, da die Zahl ggf. negativ werden kann.

von uC-Anfänger (Gast)


Lesenswert?

Der Wertebereich von a,b,c und d liegt bei 0.....16348

von Karl H. (kbuchegg)


Lesenswert?

uC-Anfänger wrote:
> Der Wertebereich von a,b,c und d liegt bei 0.....16348

Also 14 Bit.
c * d  brauchen daher 28 Bit, bleiben noch 3 Bit (Vorzeichen
nicht vergessen) für die Konstante. Das ist zuwenig. Wenn
du mit den Bitzahlen nicht hochgehen kannst, musst du die
Konstanten kleiner machen. Hilft alles nichts:

M = (a/b)*(-5,411*((d*c)/(b*a))+6,450*(c/a)+3,417*(d/b)-4,422)

Du wirst von deinen Konstanten noch nicht mal die Nachkommastellen
behalten können. Ganz im Gegenteil. In den 3 verbleibenden Bit
kannst du grade mal

M / 2 = (a/b)*(-3*((d*c)/(b*a))+3*(c/a)+2*(d/b)-2)

unterbringen. (Die restliche Umwandlung über die Brüche
zur Vereinfachung des Rechenwegs bleibt gleich)

Es sei denn: Du kannst bei den a, b, c, und d noch tricksen.
jedes Bit das du einsparen kannst, kommt den Konstanten zugute.
Ich würde mal ein paar Excel Simulationen machen um zu sehen,
wie sich das auswirkt, wenn du a, b, c, d jeweils durch 2
teilst (und somit 1 Bit gewinnst, das du bei den Konstanten
einsetzen kannst).

Das du einen Fehler kriegen wirst ist klar. Die Frage ist nur:
wie gross ist die Abweichung und: ist das akzeptabel.


von Matthias (Gast)


Lesenswert?

Oder du baust dir aus drei INTEGER-WErten einen 64bit Zahl selbst.

Musst dann halt eine Routine selbst schreiben, die alles auf 16x16bit 
runterbricht (oder wahrsch. noch besser: auf ne 48bit addition) und 
entsprechende Überläufe auswertet und auf die höheren ziffernteile 
umlenkt..

von uC-Anfänger (Gast)


Lesenswert?

Ich denke dass man bei abcd jeweils durch 10 Teilen kann, also auf die 
letzte Stelle verzichten kann, da es sich bei a und c um normierte 
Spannungswerte von 0...1000V handelt, und bei b und d um normierte 
Ströme von 0,0......100,0 A.
Bei den konstanten wäre im zweifelsfall auch der verzicht auf 2 
Nachkommastellen möglich, um noch eine akzeptable Genauigkeit zu 
erreichen.

von Detlef _. (detlef_a)


Lesenswert?

Die Berechnung der Formel mit akzeptabler Genauigkeit in 32Bit Integer 
für alle Eingangsdaten halte ich nicht für so trivial. Hätte ich das 
Problem, würde ich versuchen, mir ne Source für das IEEE 32Bit floating 
format aus dem Netz zu ziehen und das zu benutzen, was ich brauche. So 
viel Code dürfte das nicht sein.

Cheers
Detlef

von uC-Anfänger (Gast)


Lesenswert?

Hab mir die ganze Aufgabe etwas einfacher vorgestellt......
Danke für eure bisherigen Tips.....

Und falls noch jemanden ne Lösung einfällt, scheut euch nicht Sie mir 
mitzuteilen!!!

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

uC-Anfänger wrote:

> Folgende Werte habe ich als Parameter:
> a = 14221
> b = 7389
> c = 11403
> d = 6898
>
> Nun benötige ich zur berechnung folgende Formel:
> M = (a/b)*(-5,411*((d*c)/(b*a))+6,450*(c/a)+3,417*(d/b)-4,422)

Das ist keine Formal, das ist eher eine Konstante ! M=-0,2129284185
Wo ist denn die abhängige Variable ?

Und wenn das geklärt ist:

Kann man das ganze nicht über eine Tabelle lösen, deren Werte man dann 
mittelt ?

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

Karl heinz Buchegger wrote:
>            3499*b*d - 5541*c*d - 4528*b^2    6605*c
> 1024*M = -------------------------------- + --------
>                        b^2                      a
>
> Wenn das immer noch nicht reicht: Im ersten Bruch
> würde noch was gehen, indem man aufteilt und b heraushebt.

         3499*b*d   5541*c*d   4528*b^2   6605*c
1024*M = -------- - -------- - -------- + ------
            b^2        b^2       b^2         a

gekürzt:

         3499*d   5541*c*d          6605*c
1024*M = ------ - -------- - 4528 + ------
            b        b^2              a

und jetzt trickreich rechnen:

alles was ich sehe sind maximal 32 Bit, bis auf den 2. Bruch, aber da 
kann man ja:

(((5541*c)/b)*d)/b  rechnen, wenn b kleiner als c und/oder d (wegen 
Genauigkeit) alternativ dreht man das etwas um. Da muß der Bregen ran 
!!!!

von detlef _a (Gast)


Lesenswert?

>>Der Wertebereich von a,b,c und d liegt bei 0.....16348<<

Werde jetzt mal für ähnliches Problem 
http://www.jhauser.us/arithmetic/SoftFloat.html benutzen. Macht ganz 
guten Eindruck.

Gute Nacht

von Chefingenieur (Gast)


Lesenswert?

Mein Gott, Karl-Heinz und Bernd, das kann ja nicht euer Ernst sein - 
geht es noch komplizierter ?

Das ganze geht peu a peu mit dem Nenner b*b, den man zuletzt per 
Reziprokwert verrechnet. Das bringt die höchste Genauigkeit.

von Karl H. (kbuchegg)


Lesenswert?

Chefingenieur wrote:

> Das ganze geht peu a peu mit dem Nenner b*b, den man zuletzt per
> Reziprokwert verrechnet. Das bringt die höchste Genauigkeit.

Was willst du uns sagen?

Das Problem ist ja nicht der Nenner. Das Problem ist der Zähler.
Wenn a und b den kompletten 16 Bit Raum ausfüllen und maximal
32 Bit Arithmetik verfügbar ist, dann hat man mit

  Konstante  a  b

ein Problem.

Oder haben wir da was übersehen? (Was ja durchaus sein kann)


von uC-Anfänger (Gast)


Lesenswert?

@Bernd:

Die Werte a,b,c,d sind keine Konstanten, sonder veränderbare Parameter.
Daher ist ien Lösung über eine Tabelle nicht möglich!!

von uC-Anfänger (Gast)


Lesenswert?

@Chefingenieur:

Kannst du deinen Lösungsansatz nochmal verdeutlichen? Versteh jetzt 
nicht auf anhieb, was du meinst...

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

> @Chefingenieur:
>
> Kannst du deinen Lösungsansatz nochmal verdeutlichen? Versteh jetzt
> nicht auf anhieb, was du meinst...

Ja,
da bin ich auch drauf gespannt!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.