Forum: PC-Programmierung Wie in C zum Quadrat?


von Blähboy (Gast)


Lesenswert?

Wie schreibe im in C einen längeren Ausdruck zum Quadrat?
(X - X_mitte)^2       funktioniert natürlich nicht, das ^ Zeichen ist 
für bitweises Xor reserviert. Gibt es da nur pow((x - x_mitte),2);   ?

: Gesperrt durch Moderator
von Cyblord -. (cyblord)


Lesenswert?

Blähboy schrieb:
> Wie schreibe im in C einen längeren Ausdruck zum Quadrat?
> (X - X_mitte)^2       funktioniert natürlich nicht, das ^ Zeichen ist
> für bitweises Xor reserviert. Gibt es da nur pow((x - x_mitte),2);   ?

Ja, es gibt IMO keinen Operator dafür.

von Armin W. (arminw)


Lesenswert?

#define TERM (X - X_mitte)

TERM*TERM

von Hmmm (Gast)


Lesenswert?

Wenn eine weitere Zeile OK ist: x*=x;

von Armin W. (arminw)


Lesenswert?

dann muss er den langen term widerholen ;)

von Hmmm (Gast)


Lesenswert?

Armin W. schrieb:
> dann muss er den langen term widerholen ;)

Ich meinte eher:

x=[...langer Term...];
x*=x;

von W.S. (Gast)


Lesenswert?

Blähboy schrieb:
> Wie schreibe im in C einen längeren Ausdruck zum Quadrat?

Indem du diesen Term einmal berechnest, in eine Variable stopfst und 
dann diese mit sich selbst multiplizierst.

In was für einem Kindergarten sind wir denn hier???

W.S.

von Heiko L. (zer0)


Lesenswert?


Beitrag #6173046 wurde von einem Moderator gelöscht.
Beitrag #6173063 wurde von einem Moderator gelöscht.
von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Fritz Kuckuck schrieb im Beitrag #6173046:
> W.S. schrieb:
>> In was für einem Kindergarten sind wir denn hier???
>>
>> W.S.
>
> Gereizte Leute viel ich find!
> Doch wo sind die, die reizend sind?

Und ich finde das war noch diplomatisch ausgedrückt.

von Sven B. (scummos)


Lesenswert?

Armin W. schrieb:
> #define TERM (X - X_mitte)
>
> TERM*TERM

och nö bitte nicht, man muss nicht jeden Kack mit dem Präprozessor 
hinmurksen. Es gibt genug andere Möglichkeiten.

von sid (Gast)


Lesenswert?

wassn aus *math.h* geworden?
pow(x,2) 'd die nichtmehr in C?

von M. K. (sylaina)


Lesenswert?

sid schrieb:
> wassn aus *math.h* geworden?
> pow(x,2) 'd die nichtmehr in C?

Frage nicht gelesen/verstanden? Der TE hat doch gefragt ob es da noch 
was anderes gibt außer pow() ;)

von sid (Gast)


Lesenswert?

M. K. schrieb:
> Frage nicht gelesen

auweh.. moi gehört in Morpheus Arme ;)

von Sven B. (scummos)


Lesenswert?

pow(x, 2) ist viel langsamer als x*x

von Dirk B. (dirkb2)


Lesenswert?

Sven B. schrieb:
> pow(x, 2) ist viel langsamer als x*x

Ja.
Das weiß auch der Compiler und optimiert das, wenn er darf.

von Sven B. (scummos)


Lesenswert?

Dirk B. schrieb:
> Sven B. schrieb:
>> pow(x, 2) ist viel langsamer als x*x
>
> Ja.
> Das weiß auch der Compiler und optimiert das, wenn er darf.

Hast du mal ein Beispiel für einen Compiler, der pow(x, 2) in x*x 
optimiert für x double? Ich kenne keinen der das tut.

Beitrag #6173839 wurde von einem Moderator gelöscht.
von Jemand (Gast)


Lesenswert?

Sven B. schrieb:
> Hast du mal ein Beispiel für einen Compiler, der pow(x, 2) in x*x
> optimiert für x double? Ich kenne keinen der das tut.

GCC, Clang.

von GeraldB (Gast)


Lesenswert?

Wo ist jetzt das Problem?

Du kannst

1. eine eigene Funktion mit Y = X * X definieren  oder

2. (etwas komplizierter) Y = exp(log(x - x_mitte)*2);

von vn nn (Gast)


Lesenswert?

Sven B. schrieb:
> Dirk B. schrieb:
>> Sven B. schrieb:
>>> pow(x, 2) ist viel langsamer als x*x
>>
>> Ja.
>> Das weiß auch der Compiler und optimiert das, wenn er darf.
>
> Hast du mal ein Beispiel für einen Compiler, der pow(x, 2) in x*x
> optimiert für x double? Ich kenne keinen der das tut.
1
#include <math.h>
2
3
int main(void)
4
{
5
    volatile double x = 42.0;
6
7
    volatile double y1 = x * x;
8
    volatile double y2 = pow(x, 2);
9
}

x86-64 gcc 9.2 mit -O3:
1
main:                                   # @main
2
        main:
3
        movsd   xmm0, QWORD PTR .LC0[rip]
4
        xor     eax, eax
5
        movsd   QWORD PTR [rsp-24], xmm0
6
        movsd   xmm0, QWORD PTR [rsp-24]
7
        movsd   xmm1, QWORD PTR [rsp-24]
8
        mulsd   xmm0, xmm1
9
        movsd   QWORD PTR [rsp-16], xmm0
10
        movsd   xmm0, QWORD PTR [rsp-24]
11
        mulsd   xmm0, xmm0
12
        movsd   QWORD PTR [rsp-8], xmm0
13
        ret
14
.LC0:
15
        .long   0
16
        .long   1078263808
https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:14,j:1,lang:___c,selection:(endColumn:2,endLineNumber:9,positionColumn:2,positionLineNumber:9,selectionStartColumn:2,selectionStartLineNumber:9,startColumn:2,startLineNumber:9),source:'%23include+%3Cmath.h%3E%0A%0Aint+main(void)%0A%7B%0A++++volatile+double+x+%3D+42.0%3B%0A%0A++++volatile+double+y1+%3D+x+*+x%3B%0A++++volatile+double+y2+%3D+pow(x,+2)%3B%0A%7D'),l:'5',n:'0',o:'C+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:cg92,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'1',trim:'1'),fontScale:14,j:1,lang:___c,libs:!(),options:'-O3',selection:(endColumn:9,endLineNumber:10,positionColumn:9,positionLineNumber:10,selectionStartColumn:9,selectionStartLineNumber:10,startColumn:9,startLineNumber:10),source:1),l:'5',n:'0',o:'x86-64+gcc+9.2+(Editor+%231,+Compiler+%231)+C',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4

clang 9.2 x86-64 mit -O3:
1
main:                                   # @main
2
        movabs  rax, 4631107791820423168
3
        mov     qword ptr [rsp - 24], rax
4
        movsd   xmm0, qword ptr [rsp - 24] # xmm0 = mem[0],zero
5
        mulsd   xmm0, qword ptr [rsp - 24]
6
        movsd   qword ptr [rsp - 8], xmm0
7
        movsd   xmm0, qword ptr [rsp - 24] # xmm0 = mem[0],zero
8
        mulsd   xmm0, xmm0
9
        movsd   qword ptr [rsp - 16], xmm0
10
        xor     eax, eax
11
        ret
https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:14,j:1,lang:___c,selection:(endColumn:2,endLineNumber:9,positionColumn:2,positionLineNumber:9,selectionStartColumn:2,selectionStartLineNumber:9,startColumn:2,startLineNumber:9),source:'%23include+%3Cmath.h%3E%0A%0Aint+main(void)%0A%7B%0A++++volatile+double+x+%3D+42.0%3B%0A%0A++++volatile+double+y1+%3D+x+*+x%3B%0A++++volatile+double+y2+%3D+pow(x,+2)%3B%0A%7D'),l:'5',n:'0',o:'C+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:cclang900,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'1',trim:'1'),fontScale:14,j:1,lang:___c,libs:!(),options:'-O3',selection:(endColumn:28,endLineNumber:6,positionColumn:28,positionLineNumber:6,selectionStartColumn:28,selectionStartLineNumber:6,startColumn:28,startLineNumber:6),source:1),l:'5',n:'0',o:'x86-64+clang+9.0.0+(Editor+%231,+Compiler+%231)+C',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4

Beitrag #6173893 wurde von einem Moderator gelöscht.
Beitrag #6173899 wurde von einem Moderator gelöscht.
Beitrag #6173901 wurde von einem Moderator gelöscht.
von Sven B. (scummos)


Lesenswert?

Jo stimmt, ich hatte es dort auch getestet aber vergessen die 
Optimierungen anzuschalten. ;)

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Hmm,
1
 movsd   xmm0, QWORD PTR [rsp-24]
2
 movsd   xmm1, QWORD PTR [rsp-24]
3
 mulsd   xmm0, xmm1

das ist ja schon wieder irgendwie traurig...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Tim T. schrieb:
> das ist ja schon wieder irgendwie traurig...

Was ist daran traurig? Beachte das "volatile" im C-Source. Das wurde 
wohl gemacht, damit der Compiler nicht direkt selbst das Ergebnis 
ausrechnet.

Allein schon beim Weglassen des volatile bei x
1
#include <math.h>
2
3
int main(void)
4
{
5
    double x = 42.0;
6
7
    volatile double y1 = x * x;
8
    volatile double y2 = pow(x, 2);
9
}
wird nicht mehr multiplipliziert, sondern direkt das Ergebnis in y1 und 
y2 gespeichert:
1
        movsd   xmm0, QWORD PTR .LC0[rip]
2
        xor     eax, eax
3
        movsd   QWORD PTR [rsp-16], xmm0
4
        movsd   QWORD PTR [rsp-8], xmm0
5
        ret
6
.LC0:
7
        .long   0
8
        .long   1083936768

Über das Weglassen des "volatile" bei y1 und y2 brauchen wir erst gar 
nicht zu reden. da verschwindet natürlich alles.

: Bearbeitet durch Moderator
von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Tim T. schrieb:
>> das ist ja schon wieder irgendwie traurig...
>
> Was ist daran traurig? Beachte das "volatile" im C-Source. Das wurde
> wohl gemacht, damit der Compiler nicht direkt selbst das Ergebnis
> ausrechnet.

Das traurige ist das der gcc nicht erkennt das er einfach ein
1
movsd   xmm0, QWORD PTR [rsp-24]
2
mulsd   xmm0, xmm0

oder auch ein
1
movsd   xmm0, QWORD PTR [rsp-24]
2
mulsd   xmm0, QWORD PTR [rsp-24]

machen könnte und stattdessen zwei Register lädt...

von Udo K. (Gast)


Lesenswert?

Macht der doch?  Jedenfalls wenn man das idiotische volatile 
weglaesst...
genauso der Intel Compiler.  MS cl hinkt allerdings wieder hinterher.


#include <math.h>

double sq1(double x)
{
    return x*x;
}

double sq2(double x)
{
    return pow(x, 2);
}

==>>

sq1:
  .seh_endprologue
  mulsd  %xmm0, %xmm0
  ret
  .seh_endproc
  .globl  sq2
  .def  sq2;  .scl  2;  .type  32;  .endef
  .seh_proc  sq2
sq2:
  .seh_endprologue
  mulsd  %xmm0, %xmm0
  ret
  .seh_endproc

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Udo K. schrieb:
> Macht der doch?  Jedenfalls wenn man das idiotische volatile
> weglaesst...

Der Grund fürs volatile wurde ja schon oben angeführt, die Frage ist, 
warum macht er es bei volatile nicht?

von S. R. (svenska)


Lesenswert?

Tim T. schrieb:
> Der Grund fürs volatile wurde ja schon oben angeführt,
> die Frage ist, warum macht er es bei volatile nicht?

Weil er es nicht darf. Wenn eine Variable "volatile" ist, dann ist sie 
bei jedem Zugriff neu zu lesen, sie könnte sich ja geändert haben.

von Markus F. (mfro)


Lesenswert?

1
static inline int isquare(int x) {
2
    return x * x;
3
}

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

S. R. schrieb:
> Tim T. schrieb:
>> Der Grund fürs volatile wurde ja schon oben angeführt,
>> die Frage ist, warum macht er es bei volatile nicht?
>
> Weil er es nicht darf. Wenn eine Variable "volatile" ist, dann ist sie
> bei jedem Zugriff neu zu lesen, sie könnte sich ja geändert haben.

Seufz:
1
movsd   xmm0, QWORD PTR [rsp-24]
2
movsd   xmm1, QWORD PTR [rsp-24]
3
mulsd   xmm0, xmm1

soll also besser sein als:
1
movsd   xmm0, QWORD PTR [rsp-24]
2
mulsd   xmm0, QWORD PTR [rsp-24]

Nope. Sobald du eine 2 Register Operation wie z.B. mul durchführst, geht 
das gar nicht anders als sich darauf zu verlassen das der Wert 
zwischenzeitlich nicht verändert wurde.

Abgesehen davon bekommt Clang das hin...

: Bearbeitet durch User
von Jemand (Gast)


Lesenswert?

Ich gehe weiter und behaupte das ist schlicht undefiniertes Verhalten:
1
    volatile double x = 42.0;
2
    volatile double y1 = x * x;

1) Da x als volatile ausgewiesen ist, müssen beide Multiplikatoren 
individuell ausgewertet werden (C11 5.1.2.3 6)
2) Die genannten Auswertungen sind unsequenced (C11 6.5 3)
3) Zugriff auf eine volatile Variable ist ein side effect (C11 
5.1.2.3 2)
4) unsequenced side effects, die die gleiche Variable betreffen, sind 
undefiniertes Verhalten (C11 6.5 2)

Fazit: Finger weg von volatile

von vn nn (Gast)


Lesenswert?

Tim T. schrieb:
> Hmm,
>  movsd   xmm0, QWORD PTR [rsp-24]
>  movsd   xmm1, QWORD PTR [rsp-24]
>  mulsd   xmm0, xmm1
>
> das ist ja schon wieder irgendwie traurig...

Was genau mach dich traurig daran? Ich hätte das "volatile" auch 
weglassen können, aber dann hätte der Compiler gleich 1764 daraus 
gemacht...

Tim T. schrieb:
> Frank M. schrieb:
>> Tim T. schrieb:
>>> das ist ja schon wieder irgendwie traurig...
>>
>> Was ist daran traurig? Beachte das "volatile" im C-Source. Das wurde
>> wohl gemacht, damit der Compiler nicht direkt selbst das Ergebnis
>> ausrechnet.
>
> Das traurige ist das der gcc nicht erkennt das er einfach ein
> movsd   xmm0, QWORD PTR [rsp-24]
> mulsd   xmm0, xmm0
>
> oder auch ein
> movsd   xmm0, QWORD PTR [rsp-24]
> mulsd   xmm0, QWORD PTR [rsp-24]
>
> machen könnte und stattdessen zwei Register lädt...

Natürlich erkennt er es. Du verstehst nur nicht, was "volatile" macht.

Udo K. schrieb:
> Macht der doch?  Jedenfalls wenn man das idiotische volatile
> weglaesst...

Was genau ist deiner Meinung nach idiotisch daran? Ohne "volatile" hätte 
der Compiler das Ergebnis gleich selbst ausgerechnet, eher ungeeignet, 
wenn man das Verhalten von pow() demonstriere will.
Hätte ich das "volatile" bei y1 und y2 auch weggelassen, hätte der 
Compiler gemerkt dass das Ergebnis eh nicht verwendet wird, und die 
ganze Rechnung rausgeworfen.

Tim T. schrieb:
> die Frage ist,
> warum macht er es bei volatile nicht?

Lies ein C-Buch.

Jemand schrieb:
> Fazit: Finger weg von volatile

Aber ohne volatile funktioniert das Beispiel halt nicht.
1
#include <math.h>
2
3
int main(void)
4
{
5
    double x = 42.0;
6
7
    volatile double y1 = x * x;
8
    volatile double y2 = pow(x, 2);
9
}

wird optimiert zu
1
main:
2
        movsd   xmm0, QWORD PTR .LC0[rip]
3
        xor     eax, eax
4
        movsd   QWORD PTR [rsp-16], xmm0
5
        movsd   QWORD PTR [rsp-8], xmm0
6
        ret
7
.LC0:
8
        .long   0
9
        .long   1083936768
1
#include <math.h>
2
3
int main(void)
4
{
5
    double x = 42.0;
6
7
    double y1 = x * x;
8
    double y2 = pow(x, 2);
9
}

wird gar zu
1
main:
2
        xor     eax, eax
3
        ret

Toll, wenn es darum geht in einem echten Programm unnötige 
Rechenoperationen einzusparen, aber eher schlecht, wenn man 
demonstrieren will, zu was pow(x, 2) im ungünstigen Fall kompiliert.

Beitrag #6174317 wurde von einem Moderator gelöscht.
Beitrag #6174335 wurde von einem Moderator gelöscht.
von Markus F. (mfro)


Lesenswert?

vn nn schrieb:
> Toll, wenn es darum geht in einem echten Programm unnötige
> Rechenoperationen einzusparen, aber eher schlecht, wenn man
> demonstrieren will, zu was pow(x, 2) im ungünstigen Fall kompiliert.

wenn Du nachvollziehen willst, zu was pow(x, 2) compiliert wird, 
schreib' eine Funktion und compiliere die mit -c und schau' dir an, was 
der Compiler daraus macht.
1
int isquare(int i)
2
{
3
    return pow(i, 2);
4
}

Da wird nix wegoptimiert. Die Übung überlasse ich dir.

Allerdings wurde ein "Haken" noch nicht diskutiert, der insbesondere in 
einer µC-Umgebung relevant sein kann:

gcc (zumindest, clang weiß ich nicht) macht die 'pow()'-Optimierung nur, 
wenn man nicht mit -ffreestanding übersetzt (was ja in einer 
µC-Umgebung durchaus eher mal der Fall ist).

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

vn nn schrieb:
> Was genau mach dich traurig daran? Ich hätte das "volatile" auch
> weglassen können, aber dann hätte der Compiler gleich 1764 daraus
> gemacht...

Herr, schmeiß Hirn vom Himmel. Das ist absolut klar, darum muss ja das 
volatile da hin damit der Compiler nicht direkt das vorausberechnete 
Ergebnis einträgt.

> Natürlich erkennt er es. Du verstehst nur nicht, was "volatile" macht.

Ich bin mir absolut sicher das ich das deutlich besser verstehe als du, 
nur es macht einfach keinen Sinn diese Optimierung nicht zu machen, da 
sich ausserhalb der Sequenz für die Variable nichts dadurch ändert.

> Tim T. schrieb:
>> die Frage ist,
>> warum macht er es bei volatile nicht?
>
> Lies ein C-Buch.

Ob du es glaubst oder nicht, ich hab eins gelesen, genauer gesagt waren 
es einige, dazu noch Compilerbau, Rechnerarchitektur usw. Außerdem hab 
ich Assembler und Compiler für eigene CPU Architekturen gebaut und unter 
anderem Clang und GCC auf diese Architekturen portiert. Achja, 
irgendwann hab ich auch mal ein Studium in Elektrotechnik Fachrichtung 
Informationstechnologie (Mischung aus E-Technik und Informatik) 
abgeschlossen, wobei das mittlerweile auch schon ein paar Jahre her ist.

Aber um dich nicht zu überfordern stelle ich die Frage mal neu:

"Warum meint der GCC das er
1
movsd   xmm0, QWORD PTR [rsp-24]
2
mulsd   xmm0, QWORD PTR [rsp-24]
NICHT zwischen zwei Sequenzpunkte bekommt,
1
movsd   xmm0, QWORD PTR [rsp-24]
2
movsd   xmm1, QWORD PTR [rsp-24]
3
mulsd   xmm0, xmm1
aber schon?"

Und der Vollständigkeit halber:
1
int main(void)
2
{
3
    volatile double x = 42.0;
4
    volatile double y1 = x * x;
5
}

wird beim GCC mit -O3 zu:
1
main:
2
        movsd   xmm0, QWORD PTR .LC0[rip]
3
        xor     eax, eax
4
        movsd   QWORD PTR [rsp-16], xmm0
5
        movsd   xmm0, QWORD PTR [rsp-16]
6
        movsd   xmm1, QWORD PTR [rsp-16]
7
        mulsd   xmm0, xmm1
8
        movsd   QWORD PTR [rsp-8], xmm0
9
        ret
10
.LC0:
11
        .long   0
12
        .long   1078263808

und bei CLang mit -O3 (genauer sobald irgendeine Optimierung 
angeschaltet ist) zu:
1
main:                                   # @main
2
        movabs  rax, 4631107791820423168
3
        mov     qword ptr [rsp - 16], rax
4
        movsd   xmm0, qword ptr [rsp - 16] # xmm0 = mem[0],zero
5
        mulsd   xmm0, qword ptr [rsp - 16]
6
        movsd   qword ptr [rsp - 8], xmm0
7
        xor     eax, eax
8
        ret

: Bearbeitet durch User
von vn nn (Gast)


Lesenswert?

Markus F. schrieb:
> vn nn schrieb:
>> Toll, wenn es darum geht in einem echten Programm unnötige
>> Rechenoperationen einzusparen, aber eher schlecht, wenn man
>> demonstrieren will, zu was pow(x, 2) im ungünstigen Fall kompiliert.
>
> wenn Du nachvollziehen willst, zu was pow(x, 2) compiliert wird,
> schreib' eine Funktion und compiliere die mit -c und schau' dir an, was
> der Compiler daraus macht.
> int isquare(int i)
> {
>     return pow(i, 2);
> }
>
> Da wird nix wegoptimiert. Die Übung überlasse ich dir.

Du hättest auch selbst drauf kommen können, dass ich bei goldbolt nicht 
einfach sagen kann "kompilier halt mit -c". Und ob er das bereits tut, 
hatte ich einfach keine Lust auszuprobieren.
Aber da du scheinbar zum Thema ja nix sinnvolles beizutragen hast, musst 
du dich halt jetzt auf ein "volatile" versteifen. Traurig.

Markus F. schrieb:
> gcc (zumindest, clang weiß ich nicht) macht die 'pow()'-Optimierung nur,
> wenn man nicht mit -ffreestanding übersetzt (was ja in einer
> µC-Umgebung durchaus eher mal der Fall ist).

War ja keine Zielplattform gefragt.

Tim T. schrieb:
>> Natürlich erkennt er es. Du verstehst nur nicht, was "volatile" macht.
>
> Ich bin mir absolut sicher das ich das deutlich besser verstehe als du,
> nur es macht einfach keinen Sinn diese Optimierung nicht zu machen, da
> sich ausserhalb der Sequenz für die Variable nichts dadurch ändert.

Leider macht dein Posting absoult keinen Sinn. Was genau meinst du zu 
verstehen, und welche Optimierung ist unabdingbar? Dir ist schon klar, 
dass die Oprimierung "trag einfach mal statisch 1764 ein" zwar auf einem 
realen System sinnvoll sein mag, nicht aber wenn man etwas demonstrieren 
will?

Tim T. schrieb:
> Ob du es glaubst oder nicht, ich hab eins gelesen, genauer gesagt waren
> es einige, dazu noch Compilerbau, Rechnerarchitektur usw. Außerdem hab
> ich Assembler und Compiler für eigene CPU Architekturen gebaut und unter
> anderem Clang und GCC auf diese Architekturen portiert. Achja,
> irgendwann hab ich auch mal ein Studium in Elektrotechnik Fachrichtung
> Informationstechnologie (Mischung aus E-Technik und Informatik)
> abgeschlossen, wobei das mittlerweile auch schon ein paar Jahre her ist.

Und trotzdem ist dir nicht klar, warum ein volatile an der Stelle nicht 
zu vereinbaren ist mit

Tim T. schrieb:
> Das traurige ist das der gcc nicht erkennt das er einfach ein
> movsd   xmm0, QWORD PTR [rsp-24]
> mulsd   xmm0, xmm0
>
> [...]
>
> machen könnte und stattdessen zwei Register lädt...

?
Interessant.

Tim T. schrieb:
> Aber um dich nicht zu überfordern stelle ich die Frage mal neu:
>
> "Warum meint der GCC das ermovsd   xmm0, QWORD PTR [rsp-24]
> mulsd   xmm0, QWORD PTR [rsp-24]
> NICHT zwischen zwei Sequenzpunkte bekommt,movsd   xmm0, QWORD PTR
> [rsp-24]
> movsd   xmm1, QWORD PTR [rsp-24]
> mulsd   xmm0, xmm1
> aber schon?"

Interessant, wie du deine "Frage" nun geringfügig abänderst, die Stelle, 
auf die ich mich bezog entfernst, um deinen Fehler zu vertuschen.
Natürlich nur "um mich nicht zu überfordern". Nicht, um durch 
Unflätigkeiten von deinen Fehlern abzulenken.

von Jemand (Gast)


Lesenswert?

vn nn schrieb:
> Du hättest auch selbst drauf kommen können, dass ich bei goldbolt nicht
> einfach sagen kann "kompilier halt mit -c".

Was hindert dich denn daran?

von Markus F. (mfro)


Lesenswert?

vn nn schrieb:
> Du hättest auch selbst drauf kommen können, dass ich bei goldbolt nicht
> einfach sagen kann "kompilier halt mit -c".

dann solltest Du das vielleicht mal probieren (so hättest Du dann 
wenigstens irgendwas dazugelernt). Abgesehen davon hätte ich naiv 
angenommen, daß jemand, der zu einer C-Frage den dicken Max macht, 
vielleicht eventuell tatsächlich einen eigenen Compiler hat?

vn nn schrieb:
> War ja keine Zielplattform gefragt.

Wie heisst das Forum hier gleich noch mal?

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Also mir ist es jetzt einfach zu doof weiter darauf einzugehen. Der 
Spezialist will es einfach nicht verstehen und ich hab sinnvolleres zu 
tun als mich mit einem Troll auseinander zusetzen. Für mich ist hier 
demnach EOD.

Dem Rest noch einen schönen Abend.

Beitrag #6174551 wurde von einem Moderator gelöscht.
von Icke (Gast)


Lesenswert?

X² = X * X

von S. R. (svenska)


Lesenswert?

Tim T. schrieb:
> Seufz:
> movsd   xmm0, QWORD PTR [rsp-24]
> movsd   xmm1, QWORD PTR [rsp-24]
> mulsd   xmm0, xmm1
>
> soll also besser sein als:
> movsd   xmm0, QWORD PTR [rsp-24]
> mulsd   xmm0, QWORD PTR [rsp-24]

Nein. Du hast keine Ahnung.

Du erwartest, dass im ersten Fall immer xmm0 == xmm1 gilt.
Das ist für volatile nicht garantiert, und der Compiler darf sich 
nicht darauf verlassen. Wenn die Adresse nämlich eine MMIO-Adresse 
ist, dann haben Lesevorgänge möglicherweise Nebeneffekte.

> Nope. Sobald du eine 2 Register Operation wie z.B. mul durchführst, geht
> das gar nicht anders als sich darauf zu verlassen das der Wert
> zwischenzeitlich nicht verändert wurde.

Du hast keine Ahnung. Der Wert der Variablen kann sich ändern. Wenn da 
2x "lies X aus dem Speicher" steht, dann muss der Compiler auch 2x X aus 
dem Speicher lesen, und er darf nicht annehmen, dass er 2x das gleiche 
gelesen hat.

> Abgesehen davon bekommt Clang das hin...

Betrachte ich erstmal als Bug.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

S. R. schrieb:
> Tim T. schrieb:
>> Seufz:
>> movsd   xmm0, QWORD PTR [rsp-24]
>> movsd   xmm1, QWORD PTR [rsp-24]
>> mulsd   xmm0, xmm1
>>
>> soll also besser sein als:
>> movsd   xmm0, QWORD PTR [rsp-24]
>> mulsd   xmm0, QWORD PTR [rsp-24]
>
> Nein. Du hast keine Ahnung.

Wenn du das sagst, wird das wohl deine Meinung sein.

> Du erwartest, dass im ersten Fall immer xmm0 == xmm1 gilt.
> Das ist für volatile nicht garantiert, und der Compiler darf sich
> nicht darauf verlassen. Wenn die Adresse nämlich eine MMIO-Adresse
> ist, dann haben Lesevorgänge möglicherweise Nebeneffekte.

Brauch er auch nicht, wenn du einfach mal scharf hinschauen würdest, 
wird im zweiten Fall ebenfalls eine zweiter Lesezugriff auf die Adresse 
durchgeführt, nur werden die Daten nicht überflüssigerweise in einem 
Register zwischengelagert sondern direkt verwurstet.

>> Nope. Sobald du eine 2 Register Operation wie z.B. mul durchführst, geht
>> das gar nicht anders als sich darauf zu verlassen das der Wert
>> zwischenzeitlich nicht verändert wurde.
>
> Du hast keine Ahnung. Der Wert der Variablen kann sich ändern. Wenn da
> 2x "lies X aus dem Speicher" steht, dann muss der Compiler auch 2x X aus
> dem Speicher lesen, und er darf nicht annehmen, dass er 2x das gleiche
> gelesen hat.

Auch das hast du nicht verstanden, du MUSST einen Operanden vorab in ein 
Register laden und dich dann darauf verlassen dass der zweite Operand in 
der Zwischenzeit nicht verändert wurde. Im konkreten Beispiel eben dass 
an der Adresse von x immer noch der Wert 42 drin steht, ansonsten 
könntest du gar keine Multiplikation durchführen. Sowohl im ersten als 
auch im zweiten Codestück ist das der Fall. Was nur hinzukommt ist das 
der Codeabschnitt in eine Sequenz gepackt wird und so sicherstellt das 
allgemein keine Änderungen an den volatilen Variablen vorgenommen wird.

>> Abgesehen davon bekommt Clang das hin...
>
> Betrachte ich erstmal als Bug.

Auch das wird deine Meinung sein.

So, nun ist aber wirklich Schluss für mich, hab nur noch geantwortet 
weil du dir die Mühe gemacht hast eine Antwort zu basteln und dabei so 
kräftig vor die Wand gelaufen bist das ich Mitleid hatte.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich bitte die Beteiligten, mal wieder runterzukommen.

Letztendlich ging es nicht um die Frage, ob und wie volatile wirkt, 
sondern ob pow(x, 2) zu x² vom Compiler optimiert werden kann.

Also:
1
#include <math.h>
2
3
double mysquare(double x)
4
{
5
    return x * x;
6
}
7
8
double mypow2(double x)
9
{
10
    return pow(x, 2);
11
}

wird zu:
1
mysquare:                               # @mysquare
2
        mulsd   xmm0, xmm0
3
        ret
4
mypow2:                                 # @mypow2
5
        mulsd   xmm0, xmm0
6
        ret

gcc und clang liefern hier übrigens dasselbe Ergebnis.

Ich denke, damit ist die Frage hinreichend beantwortet und ein jeder 
kann sich nun wieder wichtigeren Dingen zuwenden.

: Bearbeitet durch Moderator
von Carsten (Gast)


Lesenswert?

Nur mal so aus Neugierde, wer quadriert hier eigentlich auf kleinen 
Mikrocontrollern doubles? Da möchte ich mal ne Anwendung sehen, die das 
braucht außer vielleicht nem Sextanten. Und dann nehm ich halt einen 
potenteren µC und überlasse das Optimieren der Toolchain. Um die paar 
Cents in Serienfertigung kanns wohl kaum gehen?

von Jemand (Gast)


Angehängte Dateien:

Lesenswert?

Tim T. schrieb:
> Brauch er auch nicht, wenn du einfach mal scharf hinschauen würdest,
> wird im zweiten Fall ebenfalls eine zweiter Lesezugriff auf die Adresse
> durchgeführt, nur werden die Daten nicht überflüssigerweise in einem
> Register zwischengelagert sondern direkt verwurstet.

LLVM hat ein Tool womit man die Performancecharakteristik von Kompilaten 
statisch bewerten kann: llvm-mca. Einen krassen Unterschied sehe ich 
zwischen den Versionen damit nicht.
1
{clang|gcc} -O3 test.c -march={Architektur} -S -o - | llvm-mca -mcpu={Architektur}

von Sven B. (scummos)


Lesenswert?

Carsten schrieb:
> Nur mal so aus Neugierde, wer quadriert hier eigentlich auf
> kleinen
> Mikrocontrollern doubles? Da möchte ich mal ne Anwendung sehen, die das
> braucht außer vielleicht nem Sextanten. Und dann nehm ich halt einen
> potenteren µC und überlasse das Optimieren der Toolchain. Um die paar
> Cents in Serienfertigung kanns wohl kaum gehen?

Sensordaten auswerten? Ich habe neulich was gebaut was den 
Brechungsindex der Luft aus diversen Sensor-Inputs ausrechnet und meine 
mich zu erinnern dass das mit floats relativ knapp wurde von der 
Genauigkeit her. Die Rechnung hat leicht mal > 7 signifikante Stellen, 
obwohl alle Inputs nicht hochpräzise sind.

von Carsten (Gast)


Lesenswert?

Wer hat denn jetzt den Längsten hier? +nurmalsogefragt+

von Allwissend (Gast)


Lesenswert?

Carsten schrieb:
> Um die paar
> Cents in Serienfertigung kanns wohl kaum gehen?

Kein Profi! ;-)

von Markus F. (mfro)


Lesenswert?

Tim T. schrieb:
> So, nun ist aber wirklich Schluss für mich, hab nur noch geantwortet
> weil du dir die Mühe gemacht hast eine Antwort zu basteln und dabei so
> kräftig vor die Wand gelaufen bist das ich Mitleid hatte.

Mir unklar, wie man sich daran dermaßen ereifern kann.

vn nn schrieb:
>>>> das ist ja schon wieder irgendwie traurig...

Mir völlig unklar, wie man sich daran so dermaßen ereifern kann.

gcc sieht volatile und hält sich streng an "da steckt volatile drin, 
also darf ich nicht optimieren", während clang das offensichtlich als 
"gut, da ist ein volatile drin, aber ich kann trotzdem was optimieren" 
betrachtet.

So what? Beides nicht verkehrt. Wer Performance braucht, sollte sich gut 
überlegen, wo er ein volatile einstreut.

Dann werden gleich noch Unbeteiligte angepfiffen (ich war an diesem 
Streit bis dahin noch nicht mal ansatzweise beteiligt) und Herr Holm T. 
fühlt sich gleich noch mit herausgefordert, endlich mal wieder was 
Destruktives zu schreiben.

Kindergarten. Echt.

von Blähboy (Gast)


Lesenswert?

Frank M. schrieb:
> mysquare:                               # @mysquare
>         mulsd   xmm0, xmm0
>         ret
> mypow2:                                 # @mypow2
>         mulsd   xmm0, xmm0
>         ret
>
> gcc und clang liefern hier übrigens dasselbe Ergebnis.
>
> Ich denke, damit ist die Frage hinreichend beantwortet und ein jeder
> kann sich nun wieder wichtigeren Dingen zuwenden.

Danke liebe Leute für eure Hilfe. Btw. es ist keine uC Anwendung, 
sondern ein PC-Linux-C-Programm. Dort muss ich im innersten mehrerer 
verschachtelter Schleifen die Längen von Vektoren berechnen, Umrechnung 
Rechteck in Polarkoordinaten, einmal X,Y und dann noch im 
Farbvektorraum. So dachte ich, das der Gedanke an den Versuch einer 
Optimierung nicht ganz abwegig ist. Liebe Grüße

von Klugscheisser (Gast)


Lesenswert?

Icke schrieb:
> X² = X * X

Stimmt auffällig. AAABer:
hier geht es um

(X - Xmittel)².

Wenn ich jetzt dern Herrn Binomi(TM) bemühe ist das aber meines Wissens

(X - Xmittel)² = X² + 2*X*Xmittel - Xmittel²

oder liege ich da falsch?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Blähboy schrieb:
> Btw. es ist keine uC Anwendung, sondern ein PC-Linux-C-Programm.

Diese Info gehört ins Eröffnungsposting. Außerdem hast Du mit "µC & 
Elektronik" auch noch das falsche Forum gewählt.

Ich verschiebe das dann direkt mal.

von Klugscheisser (Gast)


Lesenswert?

Klugscheisser schrieb:
> (X - Xmittel)² = X² + 2*X*Xmittel - Xmittel²

Sorry... Vorzeichen falsch ;-)

von Mathias M. (matjes)


Lesenswert?

Jemand schrieb:
> LLVM hat ein Tool womit man die Performancecharakteristik von Kompilaten
> statisch bewerten kann: llvm-mca. Einen krassen Unterschied sehe ich
> zwischen den Versionen damit nicht.

Interessant. Verstehe ich das Richtig, beide Versionen sind exakt gleich 
schnell im default und Skylake und bei Zenver1 ist GCC sogar schneller?

: Bearbeitet durch User
von vn nn (Gast)


Lesenswert?

Jemand schrieb:
> vn nn schrieb:
>> Du hättest auch selbst drauf kommen können, dass ich bei goldbolt nicht
>> einfach sagen kann "kompilier halt mit -c".
>
> Was hindert dich denn daran?

Dass ich ausprobieren wollte, zu was "pow(x, 2)" optimiert wird, und 
nicht, welchen Funktionsumfang godbolt unterstützt. Denn genau das ist 
Thema des Threads. Threadthema ist nämlich weder "was kann godbolt 
alles", noch "ist volatile an der Stelle undefined oder nicht".
Aber faszinierend, wie sich die geballte Foreninkopmpetenz auf ein 
"volatile" in einem Demobeispiel stürzt, weil sie zum eigentlichen Thema 
nix beizutragen hat.

Markus F. schrieb:
> vn nn schrieb:
>> Du hättest auch selbst drauf kommen können, dass ich bei goldbolt nicht
>> einfach sagen kann "kompilier halt mit -c".
>
> dann solltest Du das vielleicht mal probieren (so hättest Du dann
> wenigstens irgendwas dazugelernt).

Natürlich kann ich es. Aber da ich wissen wollte, wie "pow(x, 2)" 
optimiert wird, wollte ich mich halt nicht mit Nebenbaustellen 
beschäftigen.
Klar, du hingegen machst gezielt die Nebenbaustelle auf.

Markus F. schrieb:
> Abgesehen davon hätte ich naiv
> angenommen, daß jemand, der zu einer C-Frage den dicken Max macht,
> vielleicht eventuell tatsächlich einen eigenen Compiler hat?

Falls du es noch nicht gemerkt hast, der Sinn von godbolt an der Stelle 
ist, dass man darauf verlinken kann (wegen der Nachvollziehbarkeit 
wärs).
Aber eh klar, nachdem dich das eigentliche Threadthema nicht 
interessiert, und du nur stänkern willst, interessiert dich natürlich 
auch die Nachvollziehbarkeit von themenspezifischen Postings nicht.

Markus F. schrieb:
> vn nn schrieb:
>> War ja keine Zielplattform gefragt.
>
> Wie heisst das Forum hier gleich noch mal?

Genie. Embedded kann genau so gut x86 sein. Aber hellsichtig wie du 
bist, kannst du bestimmt eine konkrete Zielplattform vorschlagen. AVR? 
PIC? ARM? RISCV?

Tim T. schrieb:
> Also mir ist es jetzt einfach zu doof weiter darauf einzugehen. Der
> Spezialist will es einfach nicht verstehen und ich hab sinnvolleres zu
> tun als mich mit einem Troll auseinander zusetzen. Für mich ist hier
> demnach EOD.

Sehr gut. Dann können endlich wieder themenrelevante Dinge diskutiert 
werden, anstatt deines Unverständnisses was "volatile" so macht.
Bis dahin wundere dich einfach weiter, warum die Variable deswegen 
zweimal gelesen wird.

Tim T. schrieb:
> Brauch er auch nicht, wenn du einfach mal scharf hinschauen würdest,
> wird im zweiten Fall ebenfalls eine zweiter Lesezugriff auf die Adresse
> durchgeführt, nur werden die Daten nicht überflüssigerweise in einem
> Register zwischengelagert sondern direkt verwurstet.

Für den Fall, dass du es noch nicht gemerkt hast: es bezieht sich hier 
jeder auf den ersten von dir gelisteten Fall, den du eleganterweise 
jetzt einfach unter den Tisch fallen lässt.

Markus F. schrieb:
> Mir völlig unklar, wie man sich daran so dermaßen ereifern kann.
>
> [...]
>
> Kindergarten. Echt.

Ich vermute, du meinst mit "Kinergarten" so Aussagen wie "dann solltest 
Du das vielleicht mal probieren (so hättest Du dann
wenigstens irgendwas dazugelernt)"? Oder sowas wie "Wie heisst das Forum 
hier gleich noch mal?", und plötzlich stellt sich raus dass x86-64 doch 
nicht so falsch war?

von T.roll (Gast)


Lesenswert?

Es ist immer wieder faszinierend, wie eine simple Programmierfrage einen 
tagelang andauernden Streit vom Zaun brechen kann.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich mache hier jetzt mal zu. Der TO hat mehr als eine Antwort bekommen 
und ist zufrieden.

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.