temporärer Wertebereichsüberlauf - wie macht man es richtig ?

Hallo,

habe mal wieder ein Problem mit gemischten Wertebereichen. :o

Speed wird scheinbar richtig berechnet, trotz das die Konstante int übersteigt. Warum klappt das?

Bei der Index_Vmax Berechnung kommt Müll raus, wenn die Multiplikation int überschreitet.
Die Werte mit denen gerechnet wird passen aber alle jederzeit in int rein.
Ich muß aber erst multiplizieren und dann dividieren wegen Rundungsfehler.
Muß ich alle beteiligten Variablen zu long machen?
Das zieht einen übelsten Rattenschwanz nach sich, weil dann woanders Vergleiche mit int auch geändert werden müßten.

unsigned long temp = T2A-T1B; // millis Differenz

int Speed = 169344/temp;   // aktuelle km/h, Bsp. 50 km/h

// alles int, Bsp. IndexVsave 450 und Vmax 85 = 38250
Index_Vmax = Index_Vsave * Vmax / Speed;   // für neue Soll km/h Einstellung

Muß ich alle beteiligten Variablen zu long machen?

Nein, es reicht, wenn einer der an der Multiplikation beteiligten ein long ist. ( oder auf long gecastet wird )
Wenn du sicher bist, dass es nach der Division wieder in ein int passt, kann das Ergebnis natürlich gleich eine int Variable sein.

Hallo,

hier muß ich nichts casten, weil die 169344 als long erkannt werden vom Compiler?

int Speed = 169344/temp;

das wäre demzufolge ausreichend?

Index_Vmax = (long) Index_Vsave * Vmax / Speed;  

oder

Index_Vmax = 1L * Index_Vsave * Vmax / Speed;

Manchmal echt verwirrend ...

Ausreichend ist beides, so wie es dasteht.

Das ist falsch:
Man muß nur aufpassen, weil bei

Index_Vmax = (long) (Index_Vsave * Vmax / Speed);

ggf. erst das Ergebnis auf long aufgeblasen wird. Wenn dann noch #defines ins Spiel kommen, kann jede Übersicht leicht verloren gehen.

Hallo,

den gesamten Mechanismus dahinter kenne ich noch nicht. Danke für den Hinweis.
Also nochmal für den Überblick.
Die Multiplikation Index_Vsave * Vmax kann temporär int überschreiten.

Hierbei wird nur Index_Vsave zu long und damit funktioniert auch die Multiplikation richtig ohne int Überlauf?
Das Ergebnis bleibt immer int.

Index_Vmax = (long) Index_Vsave * Vmax / Speed;

Hier bin ich mir nicht sicher ob alles zu long wird oder auch nur Index_Vsave?

Index_Vmax = 1L * Index_Vsave * Vmax / Speed;

Hier mit Klammern ist das Ergebnis immer long, solange das in int reinpasst gibts keine Probleme?

Index_Vmax = (long) (Index_Vsave * Vmax / Speed);

Richtig verstanden?

Die Größe der jeweils beteiligten Operanden bestimmt jede einzelne Operation und deren Ergebnis. In welcher Reihenfolge die Operationen durchgeführt werden, kann man in einfachen Formeln mit "Klammern vor Punktrechnung vor Strichrechnung" ermitteln. Die Regeln von C sind da so kompliziert, daß man mit Klammern sicherstellen sollte, welche Teile zusammengehören.

Die Zuweisung an die Ergebnisvariable ist die letzte Operation, da nützt es überhaupt nichts mehr ein int Ergebnis auf long aufzublasen - das macht der Compiler selbst wenn die Ergebnis-Variable long ist. Beim Ergebnis ist ein Cast nur hilfreich um Compiler-Warnungen zu unterdrücken, wenn die Variable kürzer ist als das Ergebnis.

Leider habe ich gegen die goldene Regel verstoßen, keine Beispiele anzugeben, wie man es nicht machen sollte :frowning:
Wenn der ganze Ausdruck eingeklammert wird, sieht der Compiler das (long) erst, wenn alles berechnet ist, und dann ist es für einen Typecast zu spät.

Hallo,

je mehr man sich reinkniet umso verrückter wird es. :slight_smile:
Mit deinen Erklärungen habe ich es jetzt verstanden.
Ich muß mir das immer wieder vor Augen führen.
Danke.