wollte ich sehen, ob GCC a - (b - c)
-(a + c) - b
mit und ohne Vorzeichen ganzen Zahlen so habe ich zwei TestsAlgebraische Reduktionen von Signed Integer Ausdrücke in C/C++
//test1.c
unsigned fooau(unsigned a, unsigned b, unsigned c) { return a - (b - c); }
signed fooas(signed a, signed b, signed c) { return a - (b - c); }
signed fooms(signed a) { return a*a*a*a*a*a; }
unsigned foomu(unsigned a) { return a*a*a*a*a*a; }
//test2.c
unsigned fooau(unsigned a, unsigned b, unsigned c) { return (a + c) - b; }
signed fooas(signed a, signed b, signed c) { return (a + c) - b; }
signed fooms(signed a) { return (a*a*a)*(a*a*a); }
unsigned foomu(unsigned a) { return (a*a*a)*(a*a*a); }
I zusammengestellt zuerst mit gcc -O3 test1.c test2.c -S
und sah die reduzieren würde Versammlung. Für beide Tests waren fooau
identisch aber fooas
war nicht.
Soweit ich unsigned arithmetische verstehen kann von the following formula
(a%n + b%n)%n = (a+b)%n
abgeleitet werden, die verwendet werden können, die unsigned Arithmetik zu zeigen ist assoziativ. Aber da signed overflow is undefined behavior diese Gleichheit nicht unbedingt für die vorzeichenbehaftete Addition gilt (d. H. Die vorzeichenbehaftete Addition ist nicht assoziativ), erklärt dies, warum GCC a - (b - c)
nicht auf (a + c) - b
für vorzeichenbehaftete Ganzzahlen reduziert hat. Aber wir können dem GCC mitteilen, diese Formel mit -fwrapv
zu verwenden. Mit dieser Option ist fooas
für beide Tests identisch.
Aber was ist mit Multiplikation? Für beide Tests wurden fooms
und foomu
auf drei Multiplikationen vereinfacht (a*a*a*a*a*a to (a*a*a)*(a*a*a)
). Aber Multiplikation kann als wiederholte Addition geschrieben werden, um unter Verwendung der Formel oben Ich denke, es kann gezeigt werden, dass
((a%n)*(b%n))%n = (a*b)%n
, die ich denken kann auch zeigen, dass unsigned modulare Multiplikation als auch assoziativ ist. Aber da GCC nur drei Multiplikationen für foomu
verwendet, zeigt dies, dass GCC annimmt, dass Vorzeichen Multiplikation ist assoziativ.
Dies scheint wie ein Widerspruch zu mir. Für Addition war arithmetische Vorzeichen nicht assoziativ, sondern für Multiplikation.
Zwei Fragen:
Ist es wahr, dass die Zugabe nicht mit unterzeichnet ganzen Zahlen ist assoziativ, aber Multiplikation ist in C/C++?
Wenn signed Überlauf für die Optimierung verwendet wird, ist nicht die Tatsache, dass GCC den algebraischen Ausdruck nicht reduziert einen Fehler zu optimieren? Wäre es nicht besser besser für die Optimierung zu verwenden
-fwrapv
(Ich verstehe, dassa - (b - c)
bis(a + c) - b
ist nicht viel von einer Reduktion, aber ich mache mir Sorgen über kompliziertere Fälle)? Bedeutet dies für die Optimierung manchmal mit-fwrapv
ist effizienter und manchmal ist es nicht?
Was passiert mit 'Fooms' und' Foomu', wenn Sie den Körper 'a * a * a * a * a' - dh. eine ** ungerade ** Anzahl von Multiplikationen? Optimieren sie immer noch dasselbe? Bei einer geraden Zahl ist das Vorzeichen irrelevant, da das Ergebnis immer positiv ist. – kdopen
@ kdopen, es ist das gleiche: 'Fooms' und' Foomu' produzieren den gleichen Code und verwenden 3 Multiplikationen für 'a * a * a * a * a'. –