Forum: Mikrocontroller und Digitale Elektronik C >>> falscher Datentyp?


von __Son´s B. (bersison)


Lesenswert?

Hallo.
Mir scheint, dass Variable der folgenden Formeln im Prog-Auszug nicht 
richtig definiert wurden.
Prog. reagiert nicht auf Änderungen Poty01, Poty02

Sollte Periode und PosWelleProzent als uint64_t definiert werden?
Wert von Var. PosWelle und NegWelle müssen nach Berechnung Ganzzahlig 
zw. 1-1000 liegen.
_______________________________________________
main...  // Nachfolgendes funktioniert nicht

uint16_t Poty01;   // aus ADC ausgelesen, 0-1023
uint16_t Poty01_alt = 0; // 0-1023
uint16_t Poty02;   // aus ADC ausgelesen, 0-1023
uint16_t Poty02_alt = 0; // 0-1023
uint16_t Periode;
uint16_t PosWelleProzent;
uint16_t PosWelle;
uint16_t NegWelle;
uint8_t Veraenderung = 0;
...
//werden unter Präprozessor-Makro definiert
FREQ_BEREICH=999;
FREQ_LOW=1;
PWM_BEREICH=90;
PWM_LOW=5;
...
Veraenderung=1;
switch(Veraenderung)
{
case 1:
Periode = FREQ_BEREICH/1024*Poty01+FREQ_LOW;
                      //nach case=1 direkt case=2 abarbeiten
case 2:
PosWelleProzent = PWM_BEREICH/1024*Poty02+PWM_LOW;
PosWelle = Periode/100*PosWelleProzent;
NegWelle = Periode-PosWelle;
break;
}
...

von Michael U. (amiga)


Lesenswert?

Hallo,

Periode = FREQ_BEREICH/1024*Poty01+FREQ_LOW;

was kommt da raus? C rechnet in Integer wenn nicht zwingend anders 
angegeben.
999/1024 = 0
0*Poty01 = 0
ü+FREQ_LOW = 1

kommt also immer 1 raus, bei der 2. Formel eben 5.

FREQ_BEREICH*Poty01/1024+FREQ_LOW könnte da eher gehen.
Da passt die Rechnung aber dann nicht in 16 Bit, also mindestens einen 
der Werte der Formael auf 32 Bit casten.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von __Son´s B. (bersison)


Lesenswert?

Michael U. schrieb:
> 999/1024 = 0
Klar, rutscht unter 0
Dürfte bei uint64_t egal sein - oder?

Michael U. schrieb:
> FREQ_BEREICH*Poty01/1024+FREQ_LOW könnte da eher gehen.
Gleiche Formel, aber auch Dezimalstellen.


PS:
Wie ist das bei uint16_t, wird erste Dezimalstelle auf/abgerundet. 
Ganzzahlig bleibt unberührt erhalten?
Bsp:
uint16_t PosWelle=9,71234;
Steht in PosWelle jetzt 9, oder 10 ?

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

__Son´s B. schrieb:
> Steht in PosWelle jetzt 9, oder 10 ?
9. Es wird einfach nur der Nachkommaanteil abgeschnitten.

von Kirsch (Gast)


Lesenswert?

__Son´s B. schrieb:
> int16_t PosWelle=9,71234;
> Steht in PosWelle jetzt 9, oder 10 ?

es wird immer abgerundet

von Michael U. (amiga)


Lesenswert?

Hallo,

__Son´s B. schrieb:
> Klar, rutscht unter 0
> Dürfte bei uint64_t egal sein - oder?

auch ein 64Bit unsigned Integer ist ein Ganzzahlwert und es kommt 0 
raus.

Gruß aus Berlin
Michael

von Markus F. (mfro)


Lesenswert?

__Son´s B. schrieb:
> uint16_t PosWelle=9,71234;
> Steht in PosWelle jetzt 9, oder 10 ?

weder noch. Das gibt einen Fehler beim Compilieren.

von P. Loetmichel (Gast)


Lesenswert?

In Bascom wär 9 rausgekommen.

von Daniel A. (daniel-a)


Lesenswert?

__Son´s B. schrieb:
> uint16_t PosWelle=9,71234;
> Steht in PosWelle jetzt 9, oder 10 ?

Wenn du um 9,71234 noch eine runde Klammer machst kommt 71234 raus.

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

Daniel A. schrieb:
> Wenn du um 9,71234 noch eine runde Klammer machst kommt 71234 raus.
Es waere 5698 ;)

von Rolf M. (rmagnus)


Lesenswert?

Kirsch schrieb:
> __Son´s B. schrieb:
>> int16_t PosWelle=9,71234;

(ich nehme mal an,  dass eigentlich 9.71234 gemeint war)

>> Steht in PosWelle jetzt 9, oder 10 ?
>
> es wird immer abgerundet

Nein, es wird der Nachkommateil abgeschnitten. Das heißt, dass im Falle 
eines negativen Wertes aufgerudet wird.

von __Son´s B. (bersison)


Lesenswert?

Michael U. schrieb:
> __Son´s B. schrieb:
>> Klar, rutscht unter 0
>> Dürfte bei uint64_t egal sein - oder?
>
> auch ein 64Bit unsigned Integer ist ein Ganzzahlwert und es kommt 0
> raus.

Stimmt - habe unter C99-Standard keine Fließkomma-Definition gefunden.
Gibts das überhaupt?
_________________________________

Kaj G. schrieb:
>> Steht in PosWelle jetzt 9, oder 10 ?
> 9. Es wird einfach nur der Nachkommaanteil abgeschnitten.
Kirsch schrieb:
>> int16_t PosWelle=9,71234;
>> Steht in PosWelle jetzt 9, oder 10 ?
>
> es wird immer abgerundet
Rolf M. schrieb:
>>> Steht in PosWelle jetzt 9, oder 10 ?
>>
>> es wird immer abgerundet
>
> Nein, es wird der Nachkommateil abgeschnitten. Das heißt, dass im Falle
> eines negativen Wertes aufgerudet wird.

Ok, damit kann man kalkulieren.
___________________________________

Markus F. schrieb:
>> uint16_t PosWelle=9,71234;
>> Steht in PosWelle jetzt 9, oder 10 ?
>
> weder noch. Das gibt einen Fehler beim Compilieren.

Mein Compiler (Atmel Studio 7.0) wirft keine Fehler raus.
___________________________________

Daniel A. schrieb:
>> uint16_t PosWelle=9,71234;
>> Steht in PosWelle jetzt 9, oder 10 ?
>
> Wenn du um 9,71234 noch eine runde Klammer machst kommt 71234 raus.
Kaj G. schrieb:
>> Wenn du um 9,71234 noch eine runde Klammer machst kommt 71234 raus.
> Es waere 5698 ;)

Was stimmt denn nun?
Welche Logik steckt dahinter.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

__Son´s B. schrieb:
> Stimmt - habe unter C99-Standard keine Fließkomma-Definition gefunden.
> Gibts das überhaupt?

Aua.

Die Datentypen double und float gibt es schon erheblich länger als 
C99.

von Darth Moan (Gast)


Lesenswert?

>> uint16_t PosWelle=9,71234;

__Son´s B. schrieb:
>>> Wenn du um 9,71234 noch eine runde Klammer machst kommt 71234 raus.
>> Es waere 5698 ;)
>
> Was stimmt denn nun?
> Welche Logik steckt dahinter.

Ohne Klammer würde eine weitere variable vom Typ uint16_t angelegt 
werden
wollen. Da würde aber der Name fehlen -> Error.

Mit Klammer ist es ein ganz normales Komma als Operator. Das Ergebnis 
des
Ausdrucks ist dann das, was rechts vom Komma steht, also 71234.

von __Son´s B. (bersison)


Lesenswert?

DANKE!

Noch eine wichtige Frage zu Berechnungen;
-------------------------
uint16_t Poty01; // Wert aus ADC kann zw.0-1023 liegen
if (Poty01<1) Poty01=1; // Berechnungssicherheit

uint16_t periode=999/1024*Poty01+5;
// oder //
uint16_t periode=999*Poty01/1024+5;
-------------------------
Frage 1:
Unterscheidet der Compiler zwischen beiden Varianten?
Frage 2:
Werden INNERHALB der Berechnungen, Dezimalstellen ordentlich mit 
Nachkomma berechnet und erst dem Ergebnis die Dezimalstellen 
abgeschnitten?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

__Son´s B. schrieb:
> Werden INNERHALB der Berechnungen, Dezimalstellen ordentlich mit
> Nachkomma berechnet

Nein, wenn Du nur Ganzzahlen angibst, wird auch nur mit Ganzzahlen 
gerechnet.

Lies ein C-Buch.

Das haben wir Dir in den vergangenen Jahren wohl schon das eine oder 
andere Mal nahegelegt, wenn ich mich recht erinnere.

von Eric B. (beric)


Lesenswert?

Darth Moan schrieb:
> was rechts vom Komma steht, also 71234.

Das ist aber mehr als in einem uint16_t passt, also wird Modulo 65536 
genommen und dann kommt 5698 raus.

von Dirk B. (dirkb2)


Lesenswert?

Der Compiler wertet den Ausdruck im mathematischem Sinn aus.
Also Klammer- vor Punkt- vor Strichrechnung.

Und der Datentyp ist der, der für die Berechnung des aktuellen 
Teilausdrucks ausreichend ist.

Fall 1:
uint16_t periode=999/1024*Poty01+5;

999/1024 ist eine Integerdivision. Keine implizite Umwandlung in float. 
Da kommt 0 raus

*Poty01 Integermultiplikation, da das vorhergehende Ergebniss auch 
Integer war und das Ergebnis negativ sein könnte (egal dass da nur 
positive Werte sind)
+ 5  Addition (geschenkt)


Fall 2

uint16_t periode=999*Poty01/1024+5;

999*Poty01 Ob das Probleme macht, hängt davon ab, wir groß ein int bei 
dir ist. Bei 16-Bit gibt es Probleme (überlauf), bei 32-Bit nicht.

Da du jetzt eine große Zahl hast, gibt es beim
/1024 kein Problem mehr.

Da es bei diesen Fällen zu unterschiedliche Ergebnisse kommt (was 
durchaus gewünscht sein kann), muss der Compiler die Fälle 
unterscheiden.


Wenn du im zweiten Fall 999L statt 999 schreibst, sollte das Problem 
behoben sein.

von Brummbär (Gast)


Lesenswert?

Dirk B. schrieb:
> 999/1024 ist eine Integerdivision. Keine implizite Umwandlung in float.
> Da kommt 0 raus

Wogegen 999.0/1024 eine Fließkommaberechnung wäre.

von __Son´s B. (bersison)


Lesenswert?

Rufus Τ. F. schrieb:
> __Son´s B. schrieb:
>> Werden INNERHALB der Berechnungen, Dezimalstellen ordentlich mit
>> Nachkomma berechnet
>
> Nein, wenn Du nur Ganzzahlen angibst, wird auch nur mit Ganzzahlen
> gerechnet.
>
> Lies ein C-Buch.
>
> Das haben wir Dir in den vergangenen Jahren wohl schon das eine oder
> andere Mal nahegelegt, wenn ich mich recht erinnere.

Tja, offensichtlich habe ich eher oberflächliche C-Fachbücher. Dort wird 
nur so dividiert, dass Ganzzahlen raus kommen - Einsteiger-Niveau.
Grundsätzlich finde ich den Verweis auf Datenblätter und Literatur 
sinnvoll, NACH einer ordentlichen, dem Einsteiger angepassten 
Beschreibung - zur Wissensvertiefung!

Gott sei dank, gibt es hier im Forum aber auch Menschen mit kostruktiven 
Anregungen.
Denen, meinen tiefen Dank!

von __Son´s B. (bersison)


Lesenswert?

Brummbär schrieb:
> Dirk B. schrieb:
>> 999/1024 ist eine Integerdivision. Keine implizite Umwandlung in float.
>> Da kommt 0 raus
>
> Wogegen 999.0/1024 eine Fließkommaberechnung wäre.

"999" ist in meinem Fall eine uint16_t Variable, die ganz woanders her 
kommt - höllische Falle...

von Dirk B. (dirkb2)


Lesenswert?

Brummbär schrieb:
> Dirk B. schrieb:
>> 999/1024 ist eine Integerdivision. Keine implizite Umwandlung in float.
>> Da kommt 0 raus
>
> Wogegen 999.0/1024 eine Fließkommaberechnung wäre.

Das wird aber auch nicht genauer als die Umstellung zum Fall 2.
Es wird aber meist langsamer als Fall 2 sein.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

__Son´s B. schrieb:
> "999" ist in meinem Fall eine uint16_t Variable, die ganz woanders her
> kommt - höllische Falle...

Aha:

__Son´s B. schrieb:
> //werden unter Präprozessor-Makro definiert
> FREQ_BEREICH=999;

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

__Son´s B. schrieb:
> Tja, offensichtlich habe ich eher oberflächliche C-Fachbücher. Dort wird
> nur so dividiert, dass Ganzzahlen raus kommen - Einsteiger-Niveau.
> Grundsätzlich finde ich den Verweis auf Datenblätter und Literatur
> sinnvoll, NACH einer ordentlichen, dem Einsteiger angepassten
> Beschreibung - zur Wissensvertiefung!

Nö, die Ausrede lasse ich nicht gelten.

von __Son´s B. (bersison)


Lesenswert?

Rufus Τ. F. schrieb:
> Nö, die Ausrede lasse ich nicht gelten.

Deine auch nicht -> Berufsblindheit!
Tatsächlich bin ich ein C-Anfänger und werde es auch mit 
1-3/uC-Prog/Jahr bleiben.

von __Son´s B. (bersison)


Lesenswert?

So, 3 Formeln sind umgestellt, 4 Var. von uint16_t auf float umgestellt 
>>> Prog läuft fehlerlos!
Danke noch einmal!!!

von Dirk B. (dirkb2)


Lesenswert?

__Son´s B. schrieb:
> So, 3 Formeln sind umgestellt, 4 Var. von uint16_t auf float umgestellt

Das ist gar nicht nötig.

Du willst das Problem nicht verstehen.

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.