Guten Tag, um bei einem ATmega16 (ADC) die Messgenauigkeit zu verbessern benutze ich folgenden Code: ADC_Wert = ADC_Wert*0.964; funktioniert, bläht den Code aber auf. ADC_Wert = ADC_Wert*247/256; das funktioniert nicht (denke das liegt am int Bereich) ADC_Wert = (ADC_Wert*247)>>8; das funktioniert nicht (kommt nur murks raus) bei float Deklarierung meckert der Kompiler Da ich im Weiteren verlauf des Programms mit ADC_Wert als integer arbeite darf nicht nach String wandeln. Da muss es doch einen eleganteren Weg geben? Danke.
@ Eric S. (eric996) >ADC_Wert = ADC_Wert*0.964; funktioniert, bläht den Code aber auf. Logisch, das ist ja auch ne Float-Multiplikation. Besser geht es mit Festkommaarithmetik. MfG Falk
@Falk Genau das möchte er ja. @Eric Versuchs mal so:
1 | ADC_Wert = (unsigned long) ADC_Wert*247/256; |
Oder auch so:
1 | ADC_Wert = ADC_Wert*247UL/256; |
Beides sollte gleichwertig sein.
Da habe ich schon mal gelesen, wenn ich das richtig sehe wird aus dem Integer ein String gemacht, brauche jedoch einen Zahlenwert.
Eric S. schrieb: > Da habe ich schon mal gelesen, wenn ich das richtig sehe wird aus dem > Integer ein String gemacht, brauche jedoch einen Zahlenwert. Nein. Da wird kein String daraus gemacht. Welchen Datentyp hat den ADC_Wert? Ich vermute mal, das das bei dir ein int ist. So jetzt nimm einfach mal an, dass ADC_Wert gleich 1024 sei. 1024 * 247 macht 252928 Autsch. Die maximale Zahl, die mit einem int darstellbar ist ist nur 32767. Das Ergebnis der Multiplikation mit 247 ist also für einen int vieeeel zu gross. Behoben wird das, indem man den Compiler zwingt die Multiplikation im Zahlenraum long oder unsigned long zu machen. Dann geht sich das aus.
Die Verwendung von Kettenbrüchen ermöglicht manchmal eine Verbesserung der Performance indem mit kleineren Brüchen, in 8-Bit oder 16- Bit Darstellung bei höherer Genauigkeit der Näherung gearbeitet wird. Beispiel mit JavaScript: http://www.henked.de/javascript/kettenbrueche.htm Beispielsweise wird die Skalierung für eine Grafik einmal über einen Kettenbruch angenähert und dann kann man alle Elemente damit auf dem Display anzeigen. Oder wie im vorliegenden Fall wenn es zeitkritisch wäre. Das Produkt im Zähler muss natürlich zuerst berechnet werden und darf keinen Überlauf provozieren. Weil der Kettenbruch konvergiert kann man die Genauigkeit wählen - hoffentlich. Dies ist manchmal besser als einfach mit 100 oder 1000 zu multiplizieren was dann zu einem Überlauf führen kann. >>ADC_Wert = (unsigned long) ADC_Wert*247/256; Das ist finde ich relativ geschickt /256 und >>8 sollte vom Compiler her optimierbar sein, es muss aber ADC_Wert = ((unsigned long) ADC_Wert*247)/256; heissen, weil "/" eine höhere Priorität hat und so die Genauigkeit verschenkt/verloren wird.
Jorge schrieb: > es muss aber > ADC_Wert = ((unsigned long) ADC_Wert*247)/256; heissen, weil "/" eine > höhere Priorität hat und so die Genauigkeit verschenkt/verloren wird. Das steht hier aber anders: http://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit%C3%A4t Diese Operatoren sind afaik gleichwertig und werden daher von links nach rechts ausgewertet.
>Diese Operatoren sind afaik gleichwertig und werden daher von links nach >rechts ausgewertet. Gut, dass ich es jetzt endlich auch gelernt habe. Sogar in Pascal ist es so. Wo ich das nun wieder herhabe ~:) Danke dafür!
@ Jorge (Gast) >0.964=241/250 Ja und? 247/256 sind aber rechentechnisch besser, weil /256 = 8 Bit recht schieben. Ändert a) an dem Grundproblem der Festkommaarithmetik wenig und b) sollte der OP beim nächsten mal besser lesen. Dort steht ziemlich am Anfang was von Überlauf vermeiden. MfG Falk
Hi Falk, >Ändert a) an dem Grundproblem der Festkommaarithmetik wenig und b) >sollte der OP beim nächsten mal besser lesen. Dort steht ziemlich am >Anfang was von Überlauf vermeiden. Du hast natürlich Recht. Gerade beim AVR, der Multiplikation drauf hat. Bei einem kleinen PIC oder wie in meinem Fall einem 386SX ohne Coprozessor sieht es anders aus. Mein Ding musste Mehrkanaldaten anzeigen (ISA). 27/28 bietet eine gute Näherung (0.9643), man kann die Multiplikation mit dem Bruch in Assembler auf Additionen und Subtraktionen zurückführen und damit einen Überlauf von vorneherein vermeiden: - Nenner subtrahieren solange bis das Ergebnis kleiner Null und mitzählen - dann solange den Messwert addieren bis grösser Null und mitzählen Also am Ende ist der Messwert 27mal addiert worden und der Nenner wurde so oft es geht abgezogen, der Rest bleibt. Dabei kommt es nie zu einem Überlauf. Ein 386 schafft die Multiplikation und Division nicht in einem Takt sodass das Vorgehen eine mehr als doppelte Geschwindigkeit für die Darstellung der Fieberkurven brachte. Der Flaschenhals war dann das Löschen des Bildschirms (300ms) was über eine Änderung der Farbpalette einer der 16 VGA-Farben entschärft wurde. Das Löschen des gesamten Schirms wurde dann in 1/16 Abschnitten "hidden" erledigt. Es hängt natürlich von der konkreten Anwendung ab, rechts Schieben ist wirklich sehr effektiv vor allem mit einem Barrel Shifter. Gruss
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.