Forum: Compiler & IDEs Vergleich von Variable mit Zahl geht nicht


von Adrian W. (adrian_w69)


Lesenswert?

Hallo

ich habe hier ein Problem, welches mir sehr komisch vorkommt.
Ich habe dieses Stück code:
1
test = result;   //ist beides uint16_t
2
    
3
if(test*1000 > test*100)
4
{
5
  PORTC |= (1<<PORTC5);  //LED an
6
}        
7
else
8
{
9
  PORTC &= ~(1<<PORTC5);  //LED aus
10
}

jetzt sollte die LED immer leuchten, oder? Nun, das tut sie aber nicht 
immer: wenn die Variable "test" bestimmte (leider unbekannte, da kein 
Display) Werte einnimmt, leuchtet sie nicht!
Klar, das *1000 resp. *100 ist unsinnig, doch es sollte trotzdem 
funktionieren.

Ich hoffe jemand kann mir weiterhelfen.

lg, adrian

von Preisfrage (Gast)


Lesenswert?

Was passiert wenn test == 0? :)

von lala (Gast)


Lesenswert?

Vielleicht solltest du test mal einen Wert zuweisen... Was wenn test 
negativ ist?
Oder=0?

von Robert R. (Gast)


Lesenswert?

Ein uint16_t kann höchstens Zahlen bis 65535 aufnehmen.
Wenn "test" einen Wert größer wie 65 enthält,
dann schlägt der Vergleich möglicherweise fehl.

Geht es denn ohne die *1000 bzw. *100?

von Adrian W. (adrian_w69)


Lesenswert?

Hallo zusammen,

erstmal vielen Dank für die schnellen Antworten!

@Preisfrage:
Wenn ich test eine 0 zuweise anstatt den Wert (vom ADC) result, dann 
leuchtet die LED nie, da 0*1000 gleich ist wie 0*100. Habe ich 
ausprobiert.

@lala:
Wenn ich "test" einen negativen Wert zuweise geht es manchmal (z.B. test 
= -500) und manchmal nicht (z.B. test = -50). Aber "test" ist ja 
unsigned?!

@Robert R.:
Ohne die *1000 resp. *100 geht es.
Ich habe es jetzt mal mit 65 ausprobiert: Vergleich ist richtig!
Bei 66: Vergleich ist falsch!

EDIT:
Aber im Vergleich if(test*1000 > test*100) wird die Variable "test" doch 
gar nicht verändert?
Und wieso optimiert der Compiler den Vergleich nicht und kürzt mit 100?




lg Adrian

von Yalu X. (yalu) (Moderator)


Lesenswert?

Adrian W. schrieb:
> Und wieso optimiert der Compiler den Vergleich nicht und kürzt mit 100?

Für die (Unsigned-)Integer-Arithmetik gibt es in C spezielle Regeln.
Auszug aus dem C-Standard:
1
A computation involving unsigned operands can never overflow, because a
2
result that cannot be represented by the resulting unsigned integer type
3
is reduced modulo the number that is one greater than the largest value
4
that can be represented by the resulting type.

Selbst wenn der Compiler so intelligent wäre, beide Operanden des
Vergleichs durch 100 zu dividieren, dürfte es dies schlichtweg nicht
tun, oder er dürfte sich nicht mehr "C-Compiler" nennen.

von Adrian W. (adrian_w69)


Lesenswert?

OK, also wird das nicht optimiert, aber welches ist denn der "resulting 
unsigned integer type"?

lg Adrian

von Dirk B. (dirkb2)


Lesenswert?

Das kommt aud die Größe vom int an.
Wenn der Wertebereich von uint16_t komplett in int abgebildet werden 
kann, dann int, sonst unsigned int.

von Kaj (Gast)


Lesenswert?

Adrian W. schrieb:
> Und wieso optimiert der Compiler den Vergleich nicht und kürzt mit 100?
Warum ist der Programmiere nicht so schlau und macht das von selbst? 
Immer schön alles aufden Compiler schieben...
Und warum machst du den Vergleich mit *100 und *1000?
warum nicht einfach mit *2 und *3?
test*3 > test*2 ist vom ergebnis her das selbe wie test*1000 > test*100

von Martin B. (martin_b97)


Lesenswert?

Hallo,

> test*3 > test*2 ist vom ergebnis her das selbe wie test*1000 > test*100

Darf der Compiler jetzt schon selbst logarithmieren, wenn er lustig ist?

Martin

von ich, nicht du (Gast)


Lesenswert?

Wo ist das problem?

Bei dem wert test=66 hast du einen überlauf von dem ersten wert
Also 66*1000=66000 was größer 2^16 ist. Durch den folglich erfolgten 
überlauf ist das ergebnis also 66000-2^16 was dann auch kleiner als 
66*100=6600 ist.
Ergo test*1000> test*100 ist false.

von Kaj (Gast)


Lesenswert?

Martin B. schrieb:
>> test*3 > test*2 ist vom ergebnis her das selbe wie test*1000 > test*100
>
> Darf der Compiler jetzt schon selbst logarithmieren, wenn er lustig ist?

Ich meine nur:
test*   3 ist immer größer als test*  2
test*1000 ist immer größer als test*100

Das Ergebnis ist damit dasselbe: die Bedingung ist immer wahr, mit dem 
unterschied, das die wahrscheinlichkeit für einen Überlauf, (was hier ja 
offensichtlich zu einem Problem führt) um ein vielfaches vermindert 
wird. ebenso könnte man auch schreiben: test*10 > test

Adrian W. schrieb:
> Klar, das *1000 resp. *100 ist unsinnig, doch es sollte trotzdem
> funktionieren.
Darauf bezogen ist eine multiplikation mit 3 bzw. 2 absolut 
gleichwertig.

von Klausi (Gast)


Lesenswert?

Man kann auch einfach if(1) schreiben. Oder es ganz weglassen. :)

von Route_66 H. (route_66)


Lesenswert?

Klausi schrieb:
> Man kann auch einfach if(1) schreiben. Oder es ganz weglassen. :)

Genau das eben NICHT!

Für Test == 0 fehlt die Elisabeth (oder besser: das Else).  ;-)

von Adrian W. (adrian_w69)


Lesenswert?

Hallo, da bin ich wieder :)

Es tut mir leid, dass ich euch nicht genauer informiert habe.
Das *1000 resp. *100 hatte es gebraucht, weil mein eigentlicher code so 
aussieht:
1
 
2
if(var1 + var2 + var3*20000 > var4*1000)
3
{
4
  PORTC |= (1<<PORTC5);  //LED an
5
}        
6
else
7
{
8
  PORTC &= ~(1<<PORTC5);  //LED aus
9
}
Die Multiplikation braucht es bei meinem Programm.

Da ich aber nicht verstanden habe, wieso es bei grossen Zahlen wie 20000 
nicht funktioniert, wollte ich das Problem eingrenzen.

Ich habe immer gedacht, dass der Typ bei einer Rechnung in einem 
Vergleich keine Rolle spielt, da der Wert (z.B. var3*20000) ja gar nicht 
der Variable (z.B. var3) zugewiesen wird.

Wieso hat eigentlich bei einem 8-Bit Mikrocontroller der Datentyp "int" 
16 Bits?

lg Adrian

von (prx) A. K. (prx)


Lesenswert?

Adrian W. schrieb:
> Wieso hat eigentlich bei einem 8-Bit Mikrocontroller der Datentyp "int"
> 16 Bits?

Weil der C Standard für "int" mindestens 16 Bits fordert.

von B. S. (bestucki)


Lesenswert?

Ein Cast an der richtigen Stelle löst dein Problem.
1
if((uint32_t)test*1000 > (uint32_t)test*100)

von Adrian W. (adrian_w69)


Lesenswert?

@ A.K.: Ah ja, klar :)
Hätte ich wissen oder nachschauen müssen.

be stucki schrieb:
> Ein Cast an der richtigen Stelle löst dein
> Problem.if((uint32_t)test*1000 > (uint32_t)test*100)
Danke

von Peter D. (peda)


Lesenswert?

Adrian W. schrieb:
> Und wieso optimiert der Compiler den Vergleich nicht und kürzt mit 100?

Der Compiler ist schlau.
Er optimiert nur dann etwas weg, wenn das am Ergebnis nichts ändert.

von Karl H. (kbuchegg)


Lesenswert?

Peter Dannegger schrieb:
> Adrian W. schrieb:
>> Und wieso optimiert der Compiler den Vergleich nicht und kürzt mit 100?
>
> Der Compiler ist schlau.
> Er optimiert nur dann etwas weg, wenn das am Ergebnis nichts ändert.

... und zwar in allen denkbaren Fällen (mit allen überhaupt möglichen 
Zahlenwerten). Nicht nur in den Fällen, an die du jetzt denkst bzw. die 
dir in den Sinn kommen.

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.