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!!!!
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.
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...
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!!!
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.
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 ;-)
16Bit*16Bit*16Bit = 48 Bit => unsigned long long (64 Bit) als nächstgrößerer Datentyp.
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
@ Johannes M.: äh, ja.. da hat mich wohl mein rechenbrett irgendwie ausgetrickst...
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?
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.
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.
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.
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.
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..
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.
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
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!!!
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 ?
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 !!!!
>>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
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.
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)
@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!!
@Chefingenieur: Kannst du deinen Lösungsansatz nochmal verdeutlichen? Versteh jetzt nicht auf anhieb, was du meinst...
> @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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.