Question

Pourquoi est-il obligatoire d'utiliser -ffast-math avec g ++ pour réaliser la vectorisation des boucles en utilisant doubles? Je n'aime pas -ffast-math Parce que je ne veux pas perdre de précision.

Était-ce utile?

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.

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

Autres lectures

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top