Autovektorisierung bei Doppel- und FSTAST-MATH
-
27-09-2019 - |
Frage
Warum ist es obligatorisch zu verwenden? -ffast-math
mit G ++, um die Vektorisierung von Schleifen mithilfe zu erreichen double
s? Ich mag es nicht -ffast-math
Weil ich keine Präzision verlieren möchte.
Lösung
Sie verlieren nicht unbedingt Präzision mit -ffast-math
. Es beeinflusst nur den Umgang mit NaN
, Inf
usw. und die Reihenfolge, in der Operationen ausgeführt werden.
Wenn Sie ein bestimmtes Code haben, in dem GCC nicht die Berechnungen neu ordnet oder vereinfacht, können Sie Variablen als verwendet werden, die mit einem verwendet werden asm
Aussage.
Zum Beispiel führt der folgende Code einen Rundungsvorgang durch f
. Die beiden jedoch f += g
und f -= g
Operationen werden wahrscheinlich von GCC optimiert:
static double moo(double f, double g)
{
g *= 4503599627370496.0; // 2 ** 52
f += g;
f -= g;
return f;
}
Auf x86_64 können Sie dies verwenden asm
Aussage an die Anweisung von GCC, diese Optimierung nicht durchzuführen:
static double moo(double f, double g)
{
g *= 4503599627370496.0; // 2 ** 52
f += g;
__asm__("" : "+x" (f));
f -= g;
return f;
}
Sie müssen dies leider für jede Architektur anpassen. Auf PowerPC verwenden Sie +f
Anstatt von +x
.
Andere Tipps
Sehr wahrscheinlich, weil Vektorisierung bedeutet, dass Sie unterschiedliche Ergebnisse haben oder dass Sie schwimmende Punktsignale/-ausnahmen verpassen.
Wenn Sie für 32-Bit x86 zusammenstellen, dann verwenden GCC und G ++ Standard für die Verwendung des X87 für die Mathematik für Gleitpunkte. Auf 64-Bit-Standard-SSE kann und erzeugt der X87 unterschiedliche Werte für dieselbe Berechnung, sodass es unwahrscheinlich ist, G ++ wird überlegen, vektorisierend zu sein, wenn es nicht garantieren kann, dass Sie die gleichen Ergebnisse erhalten -ffast-math
oder einige der Flaggen, die es einschalten.
Grundsätzlich kommt es auf die schwimmende Punktumgebung für vektorisierten Code an
-fno-math-errno -fno-trapping-math -fno-signaling-nans -fno-rounding-math
Sehen Sie sich jedoch zunächst diese Optionen an und stellen Sie sicher, dass sie die Korrektheit Ihres Programms nicht beeinflussen. -ffinite-math-only
kann auch helfen
Da -ffast-math
ermöglicht Operanden neu ordnen Dadurch kann viele Code vektorisiert werden.
Zum Beispiel, um dies zu berechnen
sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + … a[99]
Der Compiler ist erforderlich die Ergänzungen durchführen der Reihe nach ohne -ffast-math
, weil Gleitkomma Math weder kommutativ noch assoziativ ist.
- Ist die schwimmende Punktzusatzmutation und assoziativ?
- Ist die schwimmende Punktzusatzin in C ++ kommutativ?
- Sind schwimmende Punkte in C assoziativ?
- Ist schwebende Punktzusatz und Multiplikation assoziativ?
Das ist der gleiche Grund Warum Compiler können nicht optimieren a*a*a*a*a*a
zu (a*a*a)*(a*a*a)
ohne -ffast-math
Das bedeutet, dass keine Vektorisierung verfügbar ist, es sei denn, Sie haben über sehr effiziente horizontale Vektor.
Jedoch, wenn -ffast-math
ist aktiviert, der Ausdruck kann berechnet werden so was (Ansehen A7. Auto-Vectorization
)
sum0 = a[0] + a[4] + a[ 8] + … a[96]
sum1 = a[1] + a[5] + a[ 9] + … a[97]
sum2 = a[2] + a[6] + a[10] + … a[98]
sum3 = a[3] + a[7] + a[11] + … a[99]
sum’ = sum0 + sum1 + sum2 + sum3
Jetzt kann der Compiler es einfach vektorisieren, indem jede Spalte parallel hinzugefügt und dann am Ende ein horizontales Hinzufügen durchführen
Tut
sum’ == sum
? Nur wenn(a[0]+a[4]+…) + (a[1]+a[5]+…) + (a[2]+a[6]+…) + ([a[3]+a[7]+…) == a[0] + a[1] + a[2] + …
Dies gilt unter der Assoziativität, die sich nicht die ganze Zeit ansiedelt. Angeben/fp:fast
Lassen Sie den Compiler Ihren Code um schneller ausführen - bis zu 4 -mal schneller für diese einfache Berechnung.Bevorzugen Sie schnell oder präzise? - A7. Autovektorisierung
Es kann von der aktiviert werden -fassociative-math
Flagge in GCC