Hallo,
simple frage ich messe eine frequenz und möchte nur kiloherz in einer
variable haben:
500000 --> in variable soll nur 500 stehen.
nun das problem:
mit
uint16_t freq;
freq = overflows * 0.256; klappt alles ich komme auf reale werte.
nur knallt er mir wegen der Gleitkommazahlen 3kb in den Flash...
freq = (overflows * 256) / 1000; gibt mir nur unsinnige Ergebnisse
(bei einer Frequenz von 77khz bekomme ich 12)
wie löse ich am besten mein Problem und warum geht mein 2. Lösungsansatz
nicht?
danke
uint_16t ist, wie der Name sagt, 16bit groß, kann also maximal
(2^16)-1=65535 annehmen. 500e3 passt da nicht rein, 500e3*256 erst recht
nicht. Du musst also mit uint_32t rechnen
Meine Hochleistungs-Kristallkugel sagt, dass deine Integers nur 16 Bit
haben, und du deswegen einen überlauf hast (77000 - 2^16 ~ 12000).
Besser wäre es, du würdest mal vollständige Informationen liefern
(welcher Prozessor/Compiler, wie ist overflows deklariert).
denke für eure Antworten...
ich wahr der Annahme das er wenn ich
freq = (overflows * 256) / 1000; rechne
dass er dann z.b. 300*256 rechnen und durch 1000 teilt und DANN erst das
Ergebnis zuweist.
Somit hätte es auch in die 16bit Variable gepasst.
Das es nicht in einen "rutsch rechnet" und dann das fertige Ergebnis
zuweist wusste ich nicht.
Dankeschön
newbie schrieb:> dass er dann z.b. 300*256 rechnen und durch 1000 teilt und DANN erst das> Ergebnis zuweist.
Ja, das ist auch der Fall, aber der GCC rechnet, wenn man es ihm nicht
anders sagt mit 16 bit. Deshalb muss man casten.
Hannis schrieb:> du hast da mit der variablendeklaration mist gemacht...>> ...ich würds lieber lassen...>>> mfg, hannis
man mach immer wieder die Erfahrung das viele vergessen wie sie selbst
mal angefangen haben...
Mann kann sich allerdings auch mit ein bischen Mathe der Sache annähern
und realisieren, dass man den ganzen Bruch durch 256 kürzen kann.
freq = overflows / 4;
Zack. Und schon stimmt dann auch das Ergebnis, weil es zu besagten
Overflow erst gar nicht kommt.
Ganz abgesehen davon, dass eine Division durch 4 für den µC ein
Kinderspiel ist, eine Division durch 1000 aber nicht.
Lukas K. schrieb:> newbie schrieb:>> dass er dann z.b. 300*256 rechnen und durch 1000 teilt und DANN erst das>> Ergebnis zuweist.>> Ja, das ist auch der Fall, aber der GCC rechnet, wenn man es ihm nicht> anders sagt mit 16 bit. Deshalb muss man casten.
Immer diese Halbwahrheiten.
Der GCC rechnet, so wie jeder andere C Compiler immer im höchsten an
einer Operation teilnehmenden Datentyp, mindestens jedoch in int.
freq = (overflows * 256) / 1000;
overflows dürfte wohl ein int sein, 256 ist ein int. Also wird eine
int*int Multiplikation gemacht und das Ergebnis ist wieder ein int. Wenn
overflows von Haus aus ein long gewesen wäre, dann würde an dieser
Stelle auch eine long*long Multiplikation durchgeführt. Genauso wenn 256
ein long wäre, was sich durch einen Suffix erzwingen liesse´
overflows * 256L
----
Und da der Teilausdruck overflows * 256 eine int*int Multiplikation ist,
kommt da auch ein int Teilergebnis raus. Damit verbleibt für die
Division, dass ein int durch einen int dividiert wird und das ganze
daher auch als int-Division realisiert wird.
Hätte man geschrieben
(overflows * 256L) / 1000
dann wäre die Division ebenfalls als long-Division gemacht worden.
Warum? Weil der linke Teilausdruck der Division als Ergebnis einer
long*long Multiplikation ebenfalls den Datentyp long hat. Damit steht
aus Sicht der Division die Sache so aus, dass sie einen long durch einen
int dividieren soll, der kleinere der beiden Datentypen wird
entsprechend vergrößert und man landet bei einer long/long Division.
Der GCC rechnet also nicht einfach generell in 16 Bit und wenn man etwas
anderes haben will muss man casten, sondern er hält sich an die
C-Regeln. Und die sind eindeutig: entscheidend ist der Datentyp der
beteiligten Operanden einer Operation.
newbie schrieb:> denke für eure Antworten...>> ich wahr der Annahme das er wenn ich>> freq = (overflows * 256) / 1000; rechne>> dass er dann z.b. 300*256 rechnen und durch 1000 teilt und DANN erst das> Ergebnis zuweist.
Ja, tut er auch.
> Somit hätte es auch in die 16bit Variable gepasst.> Das es nicht in einen "rutsch rechnet" und dann das fertige Ergebnis> zuweist wusste ich nicht.
Wie sollte das gehen? Es gibt nun mal nicht als einzelne
Assembler-Instruktion sowas wie "Multipliziere Register x mit Register y
und dividiere das Ergebnis gleich noch durch z", sondern diese beiden
Operationen müssen natürlich separat gemacht werden. Das bedeutet aber,
daß es ein Zwischenergebnis gibt, und auch das hat eine Größe, in die es
auch reinpassen muß. Das wird dann für die Division weiterverwendet, und
deren Ergebnis wird dann an die Variable zugewiesen.
Hannis schrieb:> ...ich würds lieber lassen...newbie schrieb:> was soll ich denn lassen?Hannis schrieb:> deine kläglichen versuche, einen microcontroller zu programmieren...
Du hast nie klein angefangen oder? Du solltest mal dein Sozialverhalten
überprüfen.
Na ja... 256 / 1000 ist nicht ganz 1/4.
Man kann aber trotzdem ganzzahlig Kürzen. Mach mal eine
Primfaktorzerlegung, dann kann man da viel kürzen.
Aus 256/1000 wird 128/500, 64/250, 32/125. Ab jetzt gibt es
Rundungsfehler.
newbie schrieb:> dass er dann z.b. 300*256 rechnen
Und genau jetzt tritt ein Überlauf auf. 256*256 benötigt bereits 17Bit
zur Darstellung. Mit Vorzeichen wird die Sache dann noch lustiger :-)
tschuessle
Bernhard