Je comprends que le --ffast-math
drapeau de gcc peut considérablement augmenter la vitesse des opérations flottantes et va en dehors des normes IEEE, mais je n'arrive pas à trouver des informations sur ce qui se passe réellement quand il est activé. Quelqu'un peut-il expliquer certains détails et peut-être donner un exemple clair de la façon dont quelque chose changerait si le drapeau était activé ou désactivé?
J'ai essayé de fouiller dans SO pour des questions similaires, mais je n'ai rien trouvé expliquant le fonctionnement de ffast-math.
double
, mais varie en fonction de l'application). Une chose à noter est que les optimisations ffast-math n'apportent pas nécessairement «plus» d'arrondi. La seule raison pour laquelle ce n'est pas conforme IEEE est que la réponse est différente (quoique légèrement) de ce qui est écrit.x
est inférieur à 10, l'erreur dans l'exemple de Mystical sera vers le bas autour de 10 ^ -10. Mais six = 10e20
, l'erreur est susceptible d'être de plusieurs millions.-fassociative-math
qui est inclus dans ce-funsafe-math-optimizations
qui est à son tour activé avec-ffast-math
Pourquoi permet pas d' optimiser GCCa*a*a*a*a*a
à(a*a*a)*(a*a*a)
?-ffast-math
fait bien plus que casser la stricte conformité IEEE.Tout d'abord, bien sûr, il ne respecte pas la stricte conformité IEEE, permettant par exemple de réorganiser les instructions en quelque chose qui est mathématiquement le même (idéalement) mais pas exactement le même en virgule flottante.
Deuxièmement, il désactive le réglage
errno
après les fonctions mathématiques à instruction unique, ce qui signifie éviter d'écrire dans une variable locale de thread (cela peut faire une différence de 100% pour ces fonctions sur certaines architectures).Troisièmement, il suppose que toutes les mathématiques sont finies , ce qui signifie qu'aucune vérification de NaN (ou zéro) n'est effectuée là où elles auraient des effets néfastes. On suppose simplement que cela n'arrivera pas.
Quatrièmement, il permet des approximations réciproques pour la division et la racine carrée réciproque.
De plus, il désactive le zéro signé (le code suppose que le zéro signé n'existe pas, même si la cible le prend en charge) et l'arrondi mathématique, ce qui permet entre autres un repliement constant au moment de la compilation.
Enfin, il génère du code qui suppose qu'aucune interruption matérielle ne peut se produire en raison de la signalisation / du piégeage mathématique (c'est-à-dire que si celles-ci ne peuvent pas être désactivées sur l'architecture cible et se produisent par conséquent , elles ne seront pas traitées).
la source
-ffast-math
Définit -fno-math-errno, -funsafe-math-optimisations, -ffinite-math-only, -fno-rounding-math, -fno-signaling -nans et -fcx-limited-range. Cette option entraîne la définition de la macro de préprocesseur FAST_MATH . "et quelque chose de la glibc, comme (math.h
near math_errhandling)" Par défaut, toutes les fonctions prennent en charge à la fois errno et la gestion des exceptions. En mode mathématique rapide de gcc et si les fonctions en ligne sont définies, cela peut ne pas être vrai. "-ffast-math
permet au compilateur de couper quelques angles et de rompre certaines promesses (comme expliqué), ce qui en général n'est pas dangereux en tant que tel et ne pose aucun problème pour la plupart des gens. Pour la plupart des gens, c'est la même chose, mais plus rapidement. Cependant, si votre code suppose et s'appuie sur ces promesses, votre code peut se comporter différemment de ce à quoi vous vous attendez. Habituellement, cela signifie que le programme semble fonctionner correctement, la plupart du temps, mais certains résultats peuvent être "inattendus" (par exemple, dans une simulation physique, deux objets peuvent ne pas entrer en collision correctement).-O2
permet généralement "toutes" les optimisations légales, sauf celles qui tradent la taille pour la vitesse.-O3
permet également des optimisations qui troquent la taille pour la vitesse. Il maintient toujours 100% d'exactitude.-ffast-math
tente d'accélérer les opérations mathématiques en autorisant un comportement «légèrement incorrect» qui n'est généralement pas nuisible, mais qui serait considéré comme incorrect par le libellé de la norme. Si votre code est en effet très différent en vitesse sur deux compilateurs (pas seulement 1 à 2%) alors vérifiez que votre code est strictement conforme aux normes et ...#pragma omp parallel for
, et dans le corps de la boucle, vous lisez et écrivez à la fois des adresses pointées par des arguments de fonction et effectuez une quantité non négligeable de branchements. En guise de supposition sans instruction, vous pourriez éliminer les caches à partir de votre appel de threads défini par l'implémentation, et MSVC peut éviter à tort les magasins intermédiaires que les règles d'alias imposent. Impossible de dire.