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
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?
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
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.
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
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
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.
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.
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). ;-)
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
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.
@ 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
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.
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.