mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Rechnen mit Integern


Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!!!!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!!!

Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;-)

Autor: Johannes M. (johnny-m)
Datum:

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

Autor: Willi Wacker (williwacker)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Johannes M.:

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

Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.



Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: uC-Anfänger (Gast)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.


Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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..

Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!!!

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht 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 
!!!!

Autor: detlef _a (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Chefingenieur (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)


Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!!

Autor: uC-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Chefingenieur:

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

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

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

Ja,
da bin ich auch drauf gespannt!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.