Forum: Compiler & IDEs Optimiert der Compiler Formeln?


von Plankton (Gast)


Lesenswert?

Hi,

ich habe in meinem Code immer mal Konstrukte, welche aus Gründen der 
Les- und Nachvollziehbarkeit länger sein können, als sie eigentlich 
müssten. Ein Beispiel:

corrX=(((65535.0F/size)*realX)+32767)*1024.0F;

Diese Formel könnte man so vereinfachen, dass die abschließende 
Multiplikation wegfällt. Allerdings will ich im Code gerne sehen, dass 
das Ganze an dieser Stelle um den Faktor 1024 vergrößert wurde, weswegen 
ich diese Schreibweise bevorzuge.

Meine Frage: kann der Compiler das optimieren, sprich vereinfacht er mir 
diese Formel? Oder bleibt tatsächlich die umständlichere Variante im 
Code?

Danke!

von Oliver S. (oliverso)


Lesenswert?

Was auch immer "Der Compiler" ist, du kannst zumindest davon ausgehen, 
das konstante Ausdrücke schon bei der Compilierung berechnet werden. Es 
gibt auch noch weitergehende Optimierungen, aber da wirst du schon 
nachschauen müssen, was für Code für deine Zielplattform erzeugt wird.

Oliver

von Falk B. (falk)


Lesenswert?

@  Plankton (Gast)

>corrX=(((65535.0F/size)*realX)+32767)*1024.0F;

>Diese Formel könnte man so vereinfachen, dass die abschließende
>Multiplikation wegfällt. Allerdings will ich im Code gerne sehen, dass
>das Ganze an dieser Stelle um den Faktor 1024 vergrößert wurde, weswegen
>ich diese Schreibweise bevorzuge.

Was bei der Rechung mit Fließkommazahlen totaler Unsinn ist. Solche 
Tricks braucht man nur bei Festkommaarithmetik.

>Meine Frage: kann der Compiler das optimieren, sprich vereinfacht er mir
>diese Formel?

Nein, denn dann wäre das Ergebnis anders, weil zwischendurch Rundungen 
und Überläufe auftreten können. Wie die Formelinterpratation und ggf. 
Vereinfachung im Detail abläuft, sagt dir der C-Standard oder die 
C-Profi hier.

>Oder bleibt tatsächlich die umständlichere Variante im
>Code?

Ich meine, Ja.

von Plankton (Gast)


Lesenswert?

Falk B. schrieb:
>>corrX=(((65535.0F/size)*realX)+32767)*1024.0F;
>
>>Diese Formel könnte man so vereinfachen, dass die abschließende
>>Multiplikation wegfällt. Allerdings will ich im Code gerne sehen, dass
>>das Ganze an dieser Stelle um den Faktor 1024 vergrößert wurde, weswegen
>>ich diese Schreibweise bevorzuge.
>
> Was bei der Rechung mit Fließkommazahlen totaler Unsinn ist. Solche
> Tricks braucht man nur bei Festkommaarithmetik.

Verstehe ich nicht, wieso ist das Unsinn?

von c.m. (Gast)


Lesenswert?

zur nachvollziehbarkeit gibts kommentare im code.

von (prx) A. K. (prx)


Lesenswert?

Plankton schrieb:
> Verstehe ich nicht, wieso ist das Unsinn?

Die Multiplikation einer binären Fliesskommazahl mit 1024 entspricht 
ungefähr der Multiplikation einer dezimalen Fliesskommazahl mit 
10000000000 aka 1.0e10. Soll heissen: Die Mantisse wird mit 1 
multipliziert und es wird 10 zum Exponenten hinzu addiert.

Das kann man zwar machen - aber weshalb?

: Bearbeitet durch User
von Plankton (Gast)


Lesenswert?

A. K. schrieb:
> Das kann man zwar machen - aber weshalb?

Ähm, weil ich später halt einen Wert benötige, der um den Faktor 1024 
größer ist? Alternativ kann ich bei den folgenden, viel häufiger 
auftretenden Rechenoperationen auch jedes mal mit 1024 multiplizieren, 
was aber definitiv umständlicher ist, als das einmal an zentraler Stelle 
zu machen.

von abc (Gast)


Lesenswert?

Plankton schrieb:
> was aber definitiv umständlicher ist, als das einmal an zentraler Stelle
> zu machen.

Wenn die Berechnung nur sehr selten ausgeführt wird ist es meistens 
unnötig sich Gedanken über eine Optimierung bezüglich der 
Geschwindigkeit zu machen, da ist es sinnvoller eine ausreichende 
Rechengenauigkeit zu erhalten.

von Plankton (Gast)


Lesenswert?

@abc: und welche Frage hast du jetzt genau beantwortet? :-o

von Oliver S. (oliverso)


Lesenswert?

Hier mal, was ein gcc für x86 draus macht:
1
int main()
2
{
3
  volatile float realX = 0.1;
4
  volatile float size = 17.3;
5
  volatile float corrX=(((65535.0F/size)*realX)+32767)*1024.0F;
6
}
1
movss   -0x8(%rbp),%xmm1
2
00000000004015dc:   movss   0x2a54(%rip),%xmm0        # 0x404038
3
00000000004015e4:   divss   %xmm1,%xmm0
4
00000000004015e8:   movss   -0x4(%rbp),%xmm1
5
00000000004015ed:   mulss   %xmm1,%xmm0
6
00000000004015f1:   movss   0x2a43(%rip),%xmm1        # 0x40403c
7
00000000004015f9:   addss   %xmm1,%xmm0
8
00000000004015fd:   movss   0x2a3b(%rip),%xmm1        # 0x404040
9
0000000000401605:   mulss   %xmm1,%xmm0
10
0000000000401609:   movss   %xmm0,-0xc(%rbp)

und hier das selbe für AVR:
1
b8:  60 e0         ldi  r22, 0x00  ; 0
2
  ba:  7f ef         ldi  r23, 0xFF  ; 255
3
  bc:  8f e7         ldi  r24, 0x7F  ; 127
4
  be:  97 e4         ldi  r25, 0x47  ; 71
5
  c0:  0e 94 f2 00   call  0x1e4  ; 0x1e4 <__divsf3>
6
  c4:  a7 01         movw  r20, r14
7
  c6:  96 01         movw  r18, r12
8
  c8:  0e 94 b5 01   call  0x36a  ; 0x36a <__mulsf3>
9
  cc:  20 e0         ldi  r18, 0x00  ; 0
10
  ce:  3e ef         ldi  r19, 0xFE  ; 254
11
  d0:  4f ef         ldi  r20, 0xFF  ; 255
12
  d2:  56 e4         ldi  r21, 0x46  ; 70
13
  d4:  0e 94 86 00   call  0x10c  ; 0x10c <__addsf3>
14
  d8:  20 e0         ldi  r18, 0x00  ; 0
15
  da:  30 e0         ldi  r19, 0x00  ; 0
16
  dc:  40 e8         ldi  r20, 0x80  ; 128
17
  de:  54 e4         ldi  r21, 0x44  ; 68
18
  e0:  0e 94 b5 01   call  0x36a  ; 0x36a <__mulsf3>
19
  e4:  69 83         std  Y+1, r22  ; 0x01
20
  e6:  7a 83         std  Y+2, r23  ; 0x02
21
  e8:  8b 83         std  Y+3, r24  ; 0x03
22
  ea:  9c 83         std  Y+4, r25  ; 0x04

Da wird in beiden Fällen die Formel so berechnet, wie sie im Code steht.

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

Du möchtest, dass der Compiler das Distributivgesetz anwendet und aus
1
corrX=(((65535.0F/size)*realX)+32767)*1024.0F;

dieses
1
corrX=67107840.0/size*realX+33553408.0;

macht?

Nein, das tut er nicht, da dadurch ein Überlauf enstehen könnte, der in
der ursprünglichen Schreibweise nicht auftritt. Das wird in deinem
konkreten Fall zwar wahrscheinlich nicht passieren, aber der Compiler
kennt die Wertebereiche von size und realX nicht, weswegen er auf Nummer
Sicher geht und die Umformung bleiben lässt.

Anders sieht es bei Integer-Berechnungen aus, wo garantiert werden kann,
dass das Ergebnis nach der Umformung für alle Variablenwerte dasselbe
bleibt. Zumindest der GCC würde dann die gewünschte Umformung vornehmen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Du möchtest, dass der Compiler das Distributivgesetz anwendet und aus
>
1
> corrX=(((65535.0F/size)*realX)+32767)*1024.0F;
>
> dieses
>
1
> corrX=67107840.0/size*realX+33553408.0;
>
> macht?

> Nein, das tut er nicht,

...und er lässt sich auch per
1
-O3 -ffast-math -ffinite-math-only -fassociative-math -freciprocal-math
nicht davon überzeugen...

von Wilhelm M. (wimalopaan)


Lesenswert?

Man kann das Ganz in C++ durch user-defined-literals wesentlich lesbarer 
machen. Dazu kann man durch die entsprechenden Operatoren für UDTs auch 
sicherstellen, dass bei der Division von Länge und Zeit z.B. auch eine 
Geschwindigkeit heraus kommt.

Gepaar wird das ganz mit constexpr, so dass man sicher ist, dass diese 
Berechnungen auch zur Compile-Zeit ausgeführt werden.

So berechne ich bspw. die Timer-Parameter für vorgegebene 
Timer-Interrupt-Frequenzen.

Und constexpr-Ausdrücke können dann auch wieder als template-parameter 
dienen ...

von Oliver S. (oliverso)


Lesenswert?

Constexpr führt bei solchen Ausdrücken zu keiner gründlicheren 
Compilezeitberechnung als const oder auch gar kein qualifier. Der 
Compiler berechnet da sowieso so viel selber, wie er kann.

Oliver

von Wilhelm M. (wimalopaan)


Lesenswert?

Es geht ja nicht um gründlicher ...

Es geht darum, dass eine Berechnung, in der eine / mehrere Funktionen 
auftauchen, dann auch tatsächlich zur Compilezeit ausgeführt wird. Das 
hat mit const nichts zu tun.

von A. S. (Gast)


Lesenswert?

> =(((65535.0F/size)*realX)+32767)*1024.0F;

Für mich sieht das auch irgendwie schräg aus. also in hex:
(((double)(0xffff))/size)*realX)+0x7fff)*((double) 0x400));
bzw.
(((double)(0x10000-1))/size)*realX)+0x8000-1)*((double) 0x400));

Für mich sieht das so aus, als würdest Du mit den "MägicNambas" 
bestimmte "Dinge" erreichen wollen, irgendwas mit Fixpoints, wie Falk ja 
schon schrieb.

Wenn Du Dir entsprechende Inliner oder Makrso machst, ist es sicher 
klarer und ggf. vom Compiler auflösbar. Je nach dem was Du da machen 
willst z.B.:
1
#define FIX_SCALE_L(x) ((x)*0x400L)
2
#define FIX_RUND_D(x) (((double)(x))*FIX_SCALE(0xffff)+FIX_SCALE(0x7fff))
3
4
/* und im Code dann */
5
6
    corrX=FIX_RUND(realX/size);

jetzt ist die Multiplikation mit 1024 zwar per Hand doppelt, aber nur 
einmal und im Code steht (wenn Du uns sagst, was das soll) ein 
aussagekräftiger Begriff. Der Compiler arbeitet optimal, der Leser 
braucht keine Magic-Numbers (mit Zaunlatten-Problemen) zu merken.

von Plankton (Gast)


Lesenswert?

Nein, das sind keine "Magic Numbers".

von Operator S. (smkr)


Lesenswert?

Wilhelm M. schrieb:
> Gepaar wird das ganz mit constexpr, so dass man sicher ist, dass diese
> Berechnungen auch zur Compile-Zeit ausgeführt werden.

Achtung, constexpr alleine ist keine Garantie für eine Berechnung zur 
Compile Zeit. Dies wird dir auch keine Warnings erzeugen, sollte es erst 
zur Laufzeit berechnet werden.

von Wilhelm M. (wimalopaan)


Lesenswert?

Operator S. schrieb:
> Wilhelm M. schrieb:
>> Gepaar wird das ganz mit constexpr, so dass man sicher ist, dass diese
>> Berechnungen auch zur Compile-Zeit ausgeführt werden.
>
> Achtung, constexpr alleine ist keine Garantie für eine Berechnung zur
> Compile Zeit. Dies wird dir auch keine Warnings erzeugen, sollte es erst
> zur Laufzeit berechnet werden.

Du hast Recht für constexpr Funktionen.

Wenn man aber constexpr Objekte / Variablen hat, dann schon! Werden die 
mit einem Funktionswert initialisiert, der nicht constexpr sein kann, so 
bekommt man einen Fehler.

von A. S. (Gast)


Lesenswert?

Plankton schrieb:
> Nein, das sind keine "Magic Numbers".

Aha? Wir kennen Deinen Code oder Deine Aufgabe ja nicht.

von Plankton (Gast)


Lesenswert?

Achim S. schrieb:
> Plankton schrieb:
>> Nein, das sind keine "Magic Numbers".
>
> Aha? Wir kennen Deinen Code oder Deine Aufgabe ja nicht.

Ja...und? Genügt dir diese Aussage nicht? Was soll ich machen, dass du 
es glaubst - soll ich die Information für dich singen?

von Der Andere (Gast)


Lesenswert?

Plankton schrieb:
> Ja...und? Genügt dir diese Aussage nicht? Was soll ich machen, dass du
> es glaubst - soll ich die Information für dich singen?

Mal ganz langsam, du willst hier Hilfe!

Und die erste Regel in dem (und allen anderen) Forum(en) ist: 
Hinterfrage grundsätzlich alle Aussagen des TOs.

Beispiele gerade aktuell hier im Forum:

Ein Rasenmähermotor 12V 500W der aber angeblich nur 4,5A unter Last 
zieht.

Oder ein Kupferwürfel mit den Abmessungen:
"Grundfläche des Würfels ist ungefähr 35mm+35mm und die Höhe beträgt 
70mm."

von A. S. (Gast)


Lesenswert?

Plankton schrieb:
> Ja...und? Genügt dir diese Aussage nicht? Was soll ich machen, dass du
> es glaubst - soll ich die Information für dich singen?

ich multipliziere mit 3.14159265... hat aber nichts mit Pi zu tun. Wenn 
(2^10), (2^15-1) und (2^16-1) sich bei Dir zufällig ergeben, dann ist 
das halt Zufall.

Da brauchst Du uns nichts vorzusingen.

von Mark B. (markbrandis)


Lesenswert?

Plankton schrieb:
> Nein, das sind keine "Magic Numbers".

Selbstverständlich sind es magic numbers. Wenn man diese Zeile liest:

corrX=(((65535.0F/size)*realX)+32767)*1024.0F;

dann weiß man nicht, warum da gerade z.B. 32767 steht. Und nicht etwa 
32768. Oder 8192. Oder sonst irgendwas.

Das ist genau die Definition einer "magic number": Der Sinn und Zweck 
einer Zahl bleibt im Verborgenen. Und dort gehört er nicht hin.

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Weil das Wort Kommentare bis hier nur nur einmal auftaucht:

c.m. schrieb:
> zur nachvollziehbarkeit gibts kommentare im code.

Da können dann auch die Magic Numbers erklärt werden.
Richtig benannte Konstanten sind aber besser.

von Wilhelm M. (wimalopaan)


Lesenswert?

Kommentare sind auch oft zweifelhaft: denn der Kommentar altert anders 
als der Code.

Ich habs oben ja schon mal geschrieben: eigene Datentypen mit den 
entsprechenden Operatoren und user-defined-literals (obgleich ich 
vermute, dass es reiner C Code ist - allerdings könnte man auch nur 
wegen dieses Aspekts einen C++ Compiler benutzen).

von Plankton (Gast)


Lesenswert?

Der Andere schrieb:
> Plankton schrieb:
>> Ja...und? Genügt dir diese Aussage nicht? Was soll ich machen, dass du
>> es glaubst - soll ich die Information für dich singen?
>
> Mal ganz langsam, du willst hier Hilfe!

Richtig. Aber muss ich deswegen rechtsgültige Beweise vorlegen, wenn ich 
eine Rückfrage beantworte? Wenn jemandem die Antwort, die er bekommt, 
nicht passt, dann kann ich da auch nichts dafür.

Und nein, es sind trotzdem keine Magic Numbers, der Sinn ergibts sich 
aus der Genauigkeit der Eingangdsaten (es gibt mehrere Detenquellen 
unterschiedlicher Genauigkeit) und hat absolut NICHTS mit der 
eigentlichen Frage zu tun, die schon lange beantwortet wurde.

von Carl D. (jcw2)


Lesenswert?

Die 32767 könnte man natürlich auch MAX_INT16 nennen.

von Mark B. (markbrandis)


Lesenswert?

Plankton schrieb:
> Und nein, es sind trotzdem keine Magic Numbers

Doch. Sieh es einfach ein.

> der Sinn ergibts sich aus der Genauigkeit der Eingangdsaten (es gibt
> mehrere Detenquellen unterschiedlicher Genauigkeit)

Dann benennt man diese Konstanten eben so, dass man sinnvolle Namen hat 
aus denen man ersehen kann wofür sie gut sind.

> und hat absolut NICHTS mit der eigentlichen Frage zu tun, die schon lange
> beantwortet wurde.

Damit wirst Du leben müssen. Du kannst den Leuten nicht vorschreiben, 
welche Antworten sie Dir zu geben haben.

: Bearbeitet durch User
von Plankton (Gast)


Lesenswert?

Mark B. schrieb:
>> und hat absolut NICHTS mit der eigentlichen Frage zu tun, die schon lange
>> beantwortet wurde.
>
> Damit wirst Du leben müssen. Du kannst den Leuten nicht vorschreiben,
> welche Antworten sie Dir zu geben haben.

Und die Leute werden damit leben müssen, dass sie eine entsprechende 
Reaktion erhalten, wenn sie Fragen beantworten, die nicht gestellt 
werden.

Das ist in diesem Forum hier übrigens eine extreme Unsitte, anderswo ist 
die Neigung, unbedingt irgendwelchen (nutzlosen) Senf dazuzugeben, 
deutlich geringer.

von Mark B. (markbrandis)


Lesenswert?

Plankton schrieb:
> Das ist in diesem Forum hier übrigens eine extreme Unsitte, anderswo ist
> die Neigung, unbedingt irgendwelchen (nutzlosen) Senf dazuzugeben,
> deutlich geringer.

Ist klar: Der Fehler liegt immer bei den anderen, nie bei einem selbst. 
;-)

Benannte Konstanten sind eben nicht nutzlos, sondern sie tragen zu 
besserem Code bei.

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.