Forum: Mikrocontroller und Digitale Elektronik scheitert beim Dividieren :(


von newbie (Gast)


Lesenswert?

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

von Hannis (Gast)


Lesenswert?

du hast da mit der variablendeklaration mist gemacht...

...ich würds lieber lassen...


mfg, hannis

von newbie (Gast)


Lesenswert?

was soll ich denn lassen?

von Lukas K. (carrotindustries)


Lesenswert?

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
1
freq = (uint16_t)(((uint32_t)overflows * (uint32_t)256) / (uint32_t)1000);

von Hannis (Gast)


Lesenswert?

newbie schrieb:
> was soll ich denn lassen?

deine kläglichen versuche, einen microcontroller zu programmieren...

von Juergen (Gast)


Lesenswert?

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).

von Mark (Gast)


Lesenswert?

Poste mal die Schaltfrequenz und mach ein Bild von deinem Aufbau.

Schaltplan nicht vergessen!

von newbie (Gast)


Lesenswert?

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

von Lukas K. (carrotindustries)


Lesenswert?

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.

von newbie (Gast)


Lesenswert?

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...

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

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.

von max (Gast)


Lesenswert?

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.

von Bernhard S. (b_spitzer)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

Bernhard Spitzer schrieb:
> Na ja... 256 / 1000 ist nicht ganz 1/4.

Bin schon in Eckerl und schäme mich.

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.