www.mikrocontroller.net

Forum: Compiler & IDEs Makro Gleitkomma/Integer


Autor: M. I. (seventh_son)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach die Makrosubstitution
#define Rechnung1 (Wert1 / Wert2)
#define Rechnung2 ((Wert 3 / Rechnung1)+0.5)
#define Wert1 51.0
#define Wert2 23.0



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.

Autor: M. I. (seventh_son)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wär's mit...

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: M. I. (seventh_son)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: M. I. (seventh_son)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.