Vergleich von Variable mit Zahl geht nicht

#3633156
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
Gast #3633165
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?
#3633192
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
Moderator #3633226
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.
Gast #3633508
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
Gast #3633527
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.
Gast #3633638
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.
#3634423
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
#3634653
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren