Vectorisation automatique sur Double et Ffast-Math
-
27-09-2019 - |
Question
Pourquoi est-il obligatoire d'utiliser -ffast-math
avec g ++ pour réaliser la vectorisation des boucles en utilisant double
s? Je n'aime pas -ffast-math
Parce que je ne veux pas perdre de précision.
La solution
Vous ne perdez pas nécessairement de précision avec -ffast-math
. Il n'affecte que la manipulation de NaN
, Inf
etc. et l'ordre dans lequel les opérations sont effectuées.
Si vous avez un morceau de code spécifique où vous ne voulez pas que GCC soit réorganisé ou simplifie les calculs, vous pouvez marquer des variables comme étant utilisées en utilisant un asm
déclaration.
Par exemple, le code suivant effectue une opération d'arrondi sur f
. Cependant, les deux f += g
et f -= g
Les opérations sont susceptibles d'être optimisées par GCC:
static double moo(double f, double g)
{
g *= 4503599627370496.0; // 2 ** 52
f += g;
f -= g;
return f;
}
Sur x86_64, vous pouvez l'utiliser asm
Déclaration pour demander à GCC de ne pas effectuer cette optimisation:
static double moo(double f, double g)
{
g *= 4503599627370496.0; // 2 ** 52
f += g;
__asm__("" : "+x" (f));
f -= g;
return f;
}
Vous devrez malheureusement l'adapter pour chaque architecture. Sur PowerPC, utilisez +f
à la place de +x
.
Autres conseils
Très probablement parce que la vectorisation signifie que vous pouvez avoir des résultats différents, ou peut signifier que vous manquez des signaux / exceptions de points flottants.
Si vous compilez pour 32 bits x86, alors gcc et g ++ par défaut en utilisant le x87 pour les mathématiques de point flottant, sur 64 bits, ils par défaut sont SSE, mais le x87 peut et produira des valeurs différentes pour le même calcul, il est donc peu probable G ++ envisagera la vectorisation si cela ne peut pas garantir que vous obtiendrez les mêmes résultats à moins que vous n'utilisiez -ffast-math
ou certains des drapeaux qui s'allument.
Fondamentalement, cela revient à l'environnement de point flottant pour le code vectorisé peut ne pas être le même que celui du code non vectorisé, parfois d'une manière importante, si les différences n'ont pas d'importance pour vous, quelque chose comme
-fno-math-errno -fno-trapping-math -fno-signaling-nans -fno-rounding-math
Mais consultez d'abord ces options et assurez-vous qu'elles ne affectent pas l'exactitude de votre programme. -ffinite-math-only
peut aider aussi
Car -ffast-math
actif Réorganisation des opérandes ce qui permet à de nombreux code d'être vectorisés.
Par exemple pour calculer ceci
sum = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + … a[99]
Le compilateur est obligatoire Pour faire les ajouts séquentiellement sans pour autant -ffast-math
, parce que les mathématiques à virgule flottante ne sont ni commutatifs ni associatifs.
- L'addition de points flottants est-elle commutative et associative?
- L'addition de points flottants est-elle commutative en C ++?
- Les opérations de points flottants sont-ils en C associatif?
- L'addition de points flottants est-elle associative?
C'est la même raison Pourquoi les compilateurs ne peuvent pas optimiser a*a*a*a*a*a
à (a*a*a)*(a*a*a)
sans pour autant -ffast-math
Cela signifie qu'aucune vectorisation disponible, sauf si vous avez un vecteur horizontal très efficace.
Toutefois, si -ffast-math
est activé, l'expression peut être calculée comme ça (Regarder 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
Maintenant, le compilateur peut le vectoriser facilement en ajoutant chaque colonne en parallèle, puis effectuez un ajout horizontal à la fin
Fait
sum’ == sum
? Seulement si(a[0]+a[4]+…) + (a[1]+a[5]+…) + (a[2]+a[6]+…) + ([a[3]+a[7]+…) == a[0] + a[1] + a[2] + …
Cela relève de l'associativité, auxquels les flotteurs n'adhèrent pas tout le temps. En précisant/fp:fast
Permet au compilateur de transformer votre code pour s'exécuter plus rapidement - jusqu'à 4 fois plus rapidement, pour ce calcul simple.Préférez-vous rapidement ou précis? - A7. Auto-vectorisation
Il peut être activé par le -fassociative-math
Flag dans GCC