Tag miteinander,
mal angenommen ich habe zwei Integer, mit denen ich eine Berechnung
durchführen möchte. Darf dann ein Zwischenergebnis den Maximalwert eines
Integers überschreiten?
Um mich deutlicher auszudrücken:
1
int16_ta=521;
2
int16_tb=732;
3
4
int16_terg=(a*b)/100;
Es geht nicht darum, dass bei dem Ergebnis die Nachkommastellen
abgeschnitten werden, sondern darum, ob nach der Multiplikation mit dem
richtigen Zwischenergebnis weitergerechnet wird.
Wenn ja, dann warum?
Wenn nein, wie verhindere ich die Probleme am elegantesten?
Gruß
>Darf dann ein Zwischenergebnis den Maximalwert eines>Integers überschreiten?
Ja.
>ob nach der Multiplikation mit dem>richtigen Zwischenergebnis weitergerechnet wird
Nein.
>warum?
Hmmm. Na ein Integer ist nunmal nicht grösser als es gross ist. 16 Bit
bleiben 16 Bit.
>wie verhindere ich die Probleme
Drei Alternativen.
1. Von vorne herein die Ausgangsvariablen so gross wählen, dass evtl.
Zwischenergebnisse noch hineinpassen.
2. Rechnung so umstellen, das Zwischenergebnisse klein genug bleiben.
3. Variablen bzw. Ausdruck auf grösseren Typ casten (und ggf. das
Ergebnis wieder zurück)
Oder ordne (wenn möglich) die Rechenschritte anders an.
Ansonsten gäbe es da noch die Integerpromotion, die kleine Ints
automatisch aufbläst. Dazu müsste man allerdings wissen, wie groß ein
natürlicher Int auf der Plattform ist.
>Oder ordne (wenn möglich) die Rechenschritte anders an.
Das wäre Alternative Nr. 2 von mir.
Sich auf Integer Promotion zu "verlassen" um gültige Zwischenwerte zu
erreichen ist von den anzustellenden Überlegungen her gleichwertig zu
Nr. 3.
Das Problem damit ist, das die Ursache für den Vorgang im Compiler
nichts mit Deinem Problem der Zwischenwerte zu tun hat. Ein Aspekt ist,
das wenn Datentypen verwendet werden, die kleiner als der "typische"
Maschinenwert sind, eine Erweiterung auf den nächstgrösseren Integer Typ
erfolgt. Ob ein Operator in dem Zusammenhang einen Überlauf (oder
Unterlauf) erzeugen könnte spielt dabei keine Rolle. Siehe K&R, 2.
Auflage, S.189.
Der zweite Aspekt der damit unter "Integer Promotion" zusammengefasst
wird, hängt nur vom Operator und den Typen der Operanden ab. Wieder
nicht von der Frage ob ein Überlauf stattfindet (oder stattfinden
könnte). Siehe K&R, 2. Auflage, S.191
Der wesentliche Zweck dieser "Integer Promotion" ist es, die notwendigen
Implementierungen für die Operatoren zu verringern. Es werden die
Datentypen vereinheitlicht. D.h. statt z.B. eine
short-int-Multiplikation zu implementiereren wandelt man (das ist nur
ein Beispiel) das short in ein int um.
Am besten wirst Du das als Anfänger mal lesen, aber ansonsten ignorieren
und entweder durch entsprechende Typwahl oder casts die Überläufe
verhindern.
>Ein mal (int32_t) reicht aber auch ;) Nur ein Operand muss nach int32_t>gecastet werden, damit die Operation 32bittig ausgeführt wird.
Ich weiß, aber das sieht schöner aus.
;-)
Lass ich durchgehen. Aber dein Code funktioniert trotzdem nicht. Du
musst die Division durch 100 auch in 32 Bit ausführen :-) Bisher wird
einfach nur in 32 Bit multipliziert und dann wieder auf 16 Bit gestutzt.
Richtig:
>Bisher wird einfach nur in 32 Bit multipliziert>und dann wieder auf 16 Bit gestutzt.
Nein. Wie kommst Du darauf? Am besten Verweis auf die entsprechende K&R
Seite.
Mmmh schrieb:
>>Bisher wird einfach nur in 32 Bit multipliziert>>und dann wieder auf 16 Bit gestutzt.> Nein. Wie kommst Du darauf? Am besten Verweis auf die entsprechende K&R> Seite.
Das würde mich stark wundern, wenn das nicht so wäre.
Die Zeile
1
erg/=100
enthält keinen Cast nach 32 Bit, erg ist aber 16 Bit. Ergo wird die
Division in 16 Bit ausgeführt.
Dieser Zwischencast auf 32 Bit bringt bei diesem Ausdruck nix, da ja
danach wieder EXPLIZIT auf 16 Bit runtergecastet wird...
0x209 * 0x2DC = 0xD1BC.. (binaer: 1101 0001 1011 1100)
Naja in diesem Beispiel ist der Cast sowieso witzlos, da < (2^16)-1
Wie schon geschrieben funktioniert es so:
Hier hat man allerdings Nachteile in der Perfomance, da 32 Bit
Operationen auf einer 16 oder 8 Bit Maschine natuerlich deutlich laenger
dauern.
Deshalb versuche ich aus Performancegründen zuerst immer die maximal
moeglichen Wertebereiche abzustecken und danach die Operationen darauf
auszulegen..
gruss
Jupp schrieb:
> Wie schon geschrieben funktioniert es so:> int16_t erg = (int16_t) ((int32_t(a * b)) / ((int32_t)100));
Nein, so funktioniert es nicht. bei int32_t(a * b) wird die
multiplikation is 16 Bit ausgeführt und das Ergebnis in 32 Bit
gecastet.
Und der cast vor der 100 ist unnötig, das der erste Operand des / schon
32 Bit ist.
Also:
Siehe meine Version, ich habe nur geschickt Klammern eingefügt, damit
einem sofort klar wird in welcher Reihenfolge die Operatoren
abgearbeitet werden (Division zu letzt). Dafür nehme ich es in Kauf zwei
Klammern mehr zu schreiben.
Eine eigene Frage?
Dieser Thread ist über 16 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.