Forum: Compiler & IDEs Makro Gleitkomma/Integer


von M. I. (seventh_son)


Lesenswert?

Ich habe ein Makro

#define Rechnung1 (Wert1 / Wert2)

und ein weiteres

#define Rechnung2 ((Wert 3 / Rechnung1)+0.5)

Ziel ist es, in Rechnung2 einen Integer-Wert zu erhalten, der so genau 
wie möglich ist. Deshalb wird zur Rundung 0.5 addiert.

Aus dem selben Grund sind Wert1 und Wert2 als Gleitkomma-Werte 
definiert:

#define Wert1 51.0
#define Wert2 23.0

Wert3 wird zur Laufzeit bestimmt und ist ein Integer.

Wird nun Rechnung2 zu einem Int-Wert führen, oder aufgrund der Tatsache, 
dass der Operand Rechnung1 einen Gleitkommawert beisteuert, auch einen 
Gleitkomma-Wert als Ergebnis ausgeben?

von Karl H. (kbuchegg)


Lesenswert?

Mach die Makrosubstitution
1
#define Rechnung1 (Wert1 / Wert2)
2
#define Rechnung2 ((Wert 3 / Rechnung1)+0.5)
3
#define Wert1 51.0
4
#define Wert2 23.0
5
6
7
8
x = Rechnung2;

Rechnung2 expandiert zu

    ((Wert3 / Rechnung1)+0.5)

Rechnung1 expandiert zu

    ((Wert3 / (Wert1 / Wert2))+0.5)

Wert1 und Wert2 substituieren

    ((Wert3 / (51.0/23.0))+0.5)

Wert3 sei ein int. Dann sind die Datentypen des kompletten Ausdrucks

   (( int / ( double / double ) ) + double )

und jetzt wende die C-Regeln an:
Welche Operation wird zuerst ausgeführt? Was ist der Datentyp des 
Ergebnisses? Wo wird er weiterverwendet? Was ist der Datentyp dieses 
Ergebnisses? Und das machst du solange weiter, bis du den kompletten 
Ausdruck abgearbeitet hast und den Datentyp des Ergebnisses kennst.

von M. I. (seventh_son)


Lesenswert?

Zuerst (double / double), Ergebnis double.

Dann (int / double), Ergebnis double.

(double + double), Ergebnis double.

Richtig?

Würde

#define Rechnung2 (int)((Wert 3 / Rechnung1)+0.5))

Abhilfe schaffen?

von Peter (Gast)


Lesenswert?

Wie wär's mit...

#define Rechnung2 (int)(((double) Wert3 / Rechnung1)+0.5)

von Karl H. (kbuchegg)


Lesenswert?

M. I. schrieb:

> Richtig?

Korrekt!
(War doch gar nicht so schwer, oder?)

> Würde
>
> #define Rechnung2 (int)((Wert 3 / Rechnung1)+0.5))
>
> Abhilfe schaffen?

Dann wäre das Ergebnis int. Und solange das Ergebnis positiv ist, ist es 
sogar korrekt kaufmännisch gerundet :-)

von M. I. (seventh_son)


Lesenswert?

Nun gut, habe ich verstanden.

Jetzt setzen wir mal voraus, Gleitkommaarithmetik ist nicht möglich, 
also die Konstanten sind auch Integer-Werte, so dass nur Integer 
gerechnet wird.

Wie bekommt man ein möglichst genaues Ergebnis?

Ich kenne die Methode, die Hälfte des Divisors auf den Dividenden zu 
addieren, also:

#define Rechnung2 ((Wert3+Rechnung1/2)/Rechnung1)

Somit wird ja das Ergebnis kaufmännisch gerundet.

Gibt es noch eine genauere Möglichkeit? Z.B. "erweitern" des Bruches?

von Simon K. (simon) Benutzerseite


Lesenswert?

Genauer? ;) Bei Festkomma bzw. Integer? Wie das?
Die Lösung mit dem Addieren der Hälfte des Divisors ist meiner Meinung 
nach ideal (solange der Wert im positiven Bereich bleibt).

von Karl H. (kbuchegg)


Lesenswert?

M. I. schrieb:
> Nun gut, habe ich verstanden.
>
> Jetzt setzen wir mal voraus, Gleitkommaarithmetik ist nicht möglich,
> also die Konstanten sind auch Integer-Werte, so dass nur Integer
> gerechnet wird.
>
> Wie bekommt man ein möglichst genaues Ergebnis?

Indem man eine Grundregel beherzigt:
Du willst so wenig wie möglich dividieren. Und wenn du schon dividieren 
musst, dann sollte das die letzte oder eine der letzten Operationen im 
Ausdruck sein.

    a/b/c

und

    (a*c)/b

können durchaus unterschiedliche Ergebnisse haben (übrigens auch bei 
float), obwohl sie mathematisch vollkommen äquivalent sind.


> Gibt es noch eine genauere Möglichkeit? Z.B. "erweitern" des Bruches?

Die genaueste Methode ist es, den ganzen Makrounsinn zu lassen, den 
kompletten Ausdruck zunächst mal hinzuschreiben und dann so umzuformen, 
dass während der Berechnung (die ja überall int Zwischenergebnisse 
bringt) möglichst wenig durch den Wegfall der Nachkommastellen auf der 
Strecke bleibt. Dabei aber auch im Auge behalten, dass kein 
Zwischenergebnis den int-Zahlenbereich überschreiten darf.

von M. I. (seventh_son)


Lesenswert?

>Genauer? ;) Bei Festkomma bzw. Integer? Wie das?

Nunja, man könnte ja alle Rechnungen mit dem Faktor 100 beaufschlagen, 
so dass zwei Nachkommastellen nicht abgeschnitten werden und im Ergebnis 
erhalten bleiben. Erst bei der letzten Rechnung wird dann durch den 
Faktor geteilt. Man muss natürlich darauf achten, dass die Werte nicht 
zu groß für den Typ werden. Ob das letztlich genauer ist als die andere 
Methode, weiß ich nicht.

von Simon K. (simon) Benutzerseite


Lesenswert?

M. I. schrieb:
>>Genauer? ;) Bei Festkomma bzw. Integer? Wie das?
>
> Nunja, man könnte ja alle Rechnungen mit dem Faktor 100 beaufschlagen,
> so dass zwei Nachkommastellen nicht abgeschnitten werden und im Ergebnis
> erhalten bleiben.
Ja klar, einfach das Festkomma verschieben, aber beim Runden kann man 
nichts genauer machen.

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.