Forum: Compiler & IDEs Keine Vergleiche mit long möglich???


von Daniel M. (dandansen)


Lesenswert?

Hallo Leute,
ich programmiere meinen Atmega32 mit WINAVR.
Leider habe ich ein problem mit den Datentypen. Meine Stellgröße y einer 
Regelung muß ich als long int definieren, um eine hohe Verstärkung 
nutzen zu können. Leider klappen damit keinerlei logische Vergleiche.

if(y < 0)
{
  direction = 0;
  y = -y;
}

klappt nicht. Auch wenn y wirklich < 0 ist, wird die Bedingung nie 
erfüllt.

if((int) y < 0)
{
  direction = 0;
  y = -y;
}

Obiges funktioniert hingegen. Da kriege ich dann aber Probleme, wenn y 
schon zu groß wird. Dann gibt es einen Überlauf und der gecastete Wert 
wird negativ.

Auch so etwas klappt nicht:

  if(y > 3000)
  {
    y = 3000;
  }

auch nicht so:

  if(y > 3000L)
  {
    y = 3000L;
  }

Weiß jemand, wie man vernünftige long vergleiche erstellt oder 
wenigstens richtig casten kann?
Gruß,
Daniel

von Nepi (Gast)


Lesenswert?

Poste mal ein wenig mehr aus dem Code. Sollten sich mehrere if(y...) 
Abfragen untereinander befinden versuchs mal mit switch(y). Vom Gefühl 
liegts daran das zwei Abfragen zutreffen und y zweimal das Vorzeichen 
wechselt.

von Oliver (Gast)


Lesenswert?

Bei einem Typen- oder Vorzeichenproblem meckert der Compiler 
normalerweise mit einer Warnung.

Meldet der was beim Kompilieren?

Oliver

von Daniel M. (dandansen)


Lesenswert?

OK. Das Vorzeichenproblem habe ich gelöst, in dem ich das Vorzeichen des 
Fehlers checke. Der ist vom typ int und da passiert garantiert auch kein 
Überlauf.

Hier mal meine Funktion:

static int e;
static long int y;

void p_control(int x, int w)
{
  e = w - x;
  y = kp * e;

  int direction = 1;

  if(e < 0)
  {
    direction = 0;
    y = -y;
  }

  lcd_clearln();
        lcd_puti(y);
  lcd_puts(" ");
  int y_max = ICR1;

  //avoid values higher than TOP
  if(y > y_max)
  {
    y = y_max;
  }

        lcd_puti(y);
  lcd_puts(" ");
        lcd_puti(direction);
  lcd_newln();
  set_pwm(y, direction);
}

Das Problem liegt eindeutig in der zweiten if Anweisung. So funktioniert 
es nämlich:

        //avoid values higher than TOP
  if((int) y > y_max)
  {
    y = y_max;
  }

von Daniel M. (dandansen)


Lesenswert?

Weder Fehler noch Warnungen.

von Detlef _. (detlef_a)


Lesenswert?

caste doch Dein y_max mal auf long int, das liegt doch auf der Hand, 
oder habe ich was nicht gesehen ?!

Cheers
Detlef

von Daniel M. (dandansen)


Lesenswert?

Geht auch nicht:

        long int y_max = ICR1;
  //avoid values higher than TOP
  if(y > y_max)
  {
    y = y_max;
  }

Das bringt nix. Ich kann einfach keine Vergleiche mit long typen machen? 
Das kann doch nicht sein.

von Falk (Gast)


Lesenswert?

>Das bringt nix. Ich kann einfach keine Vergleiche mit long typen machen?
>Das kann doch nicht sein.

Ist es auch nicht. aber long int scheint mir komisch. Probier mal nur

long y;

MfG
Falk

von Daniel M. (dandansen)


Lesenswert?

OK. Damit funktioniert der Vergleich schon mal. Hatte diese long int 
Bezeichnung mal in einem Tutorial gesehen und dachte, daß man das unter 
c so macht.

Jetzt habe ich aber immer noch das Problem, daß der Speicherbereich von 
y zu klein ist:

  if(y > y_max)
  {
    y = y_max;
  }

wird y größer als 2^16, gibt es einen Überlauf. Auch wenn ich die 
Variable explizit als int32_t y; definiere.

von Falk (Gast)


Lesenswert?

@Daniel Meyer

>wird y größer als 2^16, gibt es einen Überlauf. Auch wenn ich die

Woran erkennst du das?

>Variable explizit als int32_t y; definiere.

long bzw. int32_t sind 32 Bit mit Vorzeichen und können damit +/- 2*10e9 
irgendwas darstellen.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

>   y = kp * e;

Was ist kp.

Wenn kp ein int ist und e ein int ist, dann
hast du wahrscheinlich hier einen sauberen Overflow.

von Karl H. (kbuchegg)


Lesenswert?

> caste doch Dein y_max mal auf long int, das liegt doch auf der Hand,
> oder habe ich was nicht gesehen ?!

Unsinn.

von Karl H. (kbuchegg)


Lesenswert?

> aber long int scheint mir komisch

Ist aber völlig richtig. Der Datentyp heist
wirklich "long int". Durch die unsägliche "implizit int"
Regel ist es allerdings möglich, dies zu einfach nur
"long" abzukürzen.

Selbiges mit "unsigned int".
Anstatt
  unsigned int i;
kannst du genausogut
  unsigned i;
schreiben.

Der Compiler denkt sich das "int" dazu, wenn er nichts
anderes hat.


von Daniel M. (dandansen)


Lesenswert?

OK. Dummer Fehler:

y = kp * e;

wobei kp und e beide int variablen sind. Gibt natürlich einen Überlauf 
bevor das Ergebnis in die long variable y geschrieben wird.

Sehen tu ich das, indem ich y ausgebe, daß später wieder < y_max wird, 
obwohl der wert eigentlich höher sein müte.

Vielen Dank

von Daniel M. (dandansen)


Lesenswert?

@ Karl Heinz B.:
Wenn ich long int nehme, wird kein Vergleich ausgeführt.

von Karl H. (kbuchegg)


Lesenswert?

Daniel Meyer wrote:
> OK. Dummer Fehler:
>
> y = kp * e;
>
> wobei kp und e beide int variablen sind. Gibt natürlich einen Überlauf
> bevor das Ergebnis in die long variable y geschrieben wird.

Eben.
Und nach einem Überlauf kannst du dich auf gar nichts
mehr verlassen. Weder auf das Vorzeichen noch auf sonst
irgendwas.

Moral von der Story:
Wenn du in deinem Programm seltsames Verhalten hast, dann
hast du in 99% aller Fälle irgendwo Mist gebaut. Es ist
ganz selten, dass in einem derart gut getesteten Compiler
wie dem gcc derart triviale Fehler auftauchen.

von Karl H. (kbuchegg)


Lesenswert?

Daniel Meyer wrote:
> @ Karl Heinz B.:
> Wenn ich long int nehme, wird kein Vergleich ausgeführt.

Dein Problem war schon lange vor dem Vergleich!!!!
Die Berechnung hat einen Overflow produziert.
Ob das Ergebnis dann positiv oder negativ ist, in
welchem Zahlenbereich es liegt, hängt von den konkreten
Zahlen ab, die zum Overflow geführt haben.


Was du siehst, sind die Symptome. Es hilft aber nichts
an den Symptomen herumzudoktorn. Du musst die Ursachen
bekämpfen. Und die Ursache ist der Overflow!

Wenn du Symptome bekämpfen willst, musst du Arzt werden.

von Daniel M. (dandansen)


Lesenswert?

Stimmt. Sorry!
Evtl. war auch ein zusätzliches Problem in der Zeile:

y = kp * e;

Wie verhält es sich, wenn kp vom Typ unsigned int und e vom Typ int ist? 
Wird dann das Ergebnis vor der Zuweisung auch unsigned berechnet?

von Matthias (Gast)


Lesenswert?

...Wenn du Symptome bekämpfen willst, musst du Arzt werden....

eher in die Politik..

von Karl H. (kbuchegg)


Lesenswert?

long double
double
float
unsigned long int    (synonymous with unsigned long)
long int             (synonymous with long)
unsigned int         (synonymous with unsigned)
int
unsigned short int   (synonymous with unsignd short)
short int            (synonymous with short)
unsigned Char
short
Char


Dies ist die Reihung. Der jeweils niedrigere Datentyp
wird auf den höheren angeglichen.

von Daniel M. (dandansen)


Lesenswert?

ALles klar. Vielen Dank nochmal! Deswegen hat mein Vergleich < 0 auch 
nicht funktionieren können. Wieder was gelernt.

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.