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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von __Son´s B. (bersison)


Bewertung
-1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

von Kirsch (Gast)


Bewertung
-1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
-1 lesenswert
nicht lesenswert
In Bascom wär 9 rausgekommen.

von Daniel A. (daniel-a)


Bewertung
0 lesenswert
nicht 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)


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

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.