9

Contexte:Existe-t-il un équivalent (Linux) g ++ aux indicateurs/fp: precise et/fp: fast utilisés dans Visual Studio?

Il y a plusieurs années, je hérité d'une base de code qui utilisait le Visual Studio (VC++) flag «/fp: rapide » pour produire un code plus rapide dans une bibliothèque de calcul lourds particulier. Malheureusement, '/ fp: fast' produisait des résultats légèrement différents de la même bibliothèque sous un autre compilateur (Borland C++). Comme nous devions produire exactement les mêmes résultats, je suis passé à '/ fp: précise', ce qui a bien fonctionné, et tout a toujours été clair. Cependant, maintenant je compile la même bibliothèque avec g ++ sur uBuntu Linux 10.04 et je vois un comportement similaire, et je me demande si cela pourrait avoir une cause similaire. Les résultats numériques de ma construction g ++ sont légèrement différents des résultats numériques de ma compilation VC++. Cela me amène à ma question:

Question:

Est-ce que g ++ ont des paramètres équivalents ou similaires aux options VC++ 'fp:: rapide' et 'précis' fp? (? Et quels sont-ils que je veux activer le 'fp: précis. Équivalent)

Plus verbeux Information:

Je Compile en utilisant make', qui appelle g ++. Pour autant que je sache (les fichiers make sont un peu énigmatiques et n'ont pas été écrits par moi), les seuls paramètres ajoutés à l'appel g ++ sont les "normaux" (inclure les dossiers et les fichiers à compiler) et -fPIC (Je ne suis pas sûr de ce que fait cet interrupteur, je ne le vois pas sur la page 'homme').

Les seuls paramètres pertinents dans 'man g ++' semblent être d'activer les options d'optimisation. (par exemple, -funsafe-math-optimizations). Cependant, je ne pense pas que j'allume quelque chose, je veux juste désactiver l'optimisation pertinente. J'ai essayé les versions Release et Debug, VC++ donne les mêmes résultats pour release et debug, et g ++ donne les mêmes résultats pour release et debug, mais je ne peux pas obtenir la version g ++ pour donner les mêmes résultats que le Version VC++.

+0

J'ai trouvé la signification de -fPIC après un peu plus de googling: -fPIC Si supporté pour la machine cible, émette un code indépendant de la position, adapté à la liaison dynamique, même si les branches (3, n) ont besoin de grands déplacements. – Boinst

+0

Cela peut prendre du temps, mais cela en vaut la peine: pouvez-vous essayer de définir la première instruction (ou au moins la ligne de code) où certains calculs divergent entre MSVC et gcc? –

+0

Oui, je travaille sur votre suggestion. Malheureusement, je suis un peu sur un linux n00b, donc ça me prend un peu de temps pour tout faire ensemble! – Boinst

Répondre

9

La précision de registre en excès est un problème uniquement sur les registres FPU, que les compilateurs (avec les commutateurs de validation appropriés) ont tendance à éviter de toute façon. Lorsque les calculs à virgule flottante sont effectués dans des registres SSE, la précision du registre est égale à celle de la mémoire. D'après mon expérience, la plus grande partie de l'impact/fp: impact rapide (et discordance potentielle) provient du compilateur qui prend la liberté d'effectuer des transformations algébriques. Cela peut être aussi simple que l'ordre de changement:

(a + b) + c --> a + (b + c) 

peut être - la distribution multiplications comme un * (b + c) à volonté, et peut se rendre à des transformations assez complexes - tous destinés à réutiliser les calculs précédents. Avec une précision infinie, de telles transformations sont bénignes, bien sûr - mais en précision finie elles changent réellement le résultat. Comme un exemple de jouet, essayez l'exemple de l'ordre-summand avec a = b = 2^(- 23), c = 1. MS Eric Fleegal describes it in much more detail. À cet égard, le commutateur gcc le plus proche de/fp: precise est -fno-unsafe-math-optimizations. Je pense que c'est par défaut - vous pouvez peut-être essayer de le définir explicitement et voir si cela fait une différence. De même, vous pouvez essayer de désactiver explicitement toutes les optimisations -fast-math: -fno-finite-math seulement, -fmath-errno, -ftrapping-math, -frounding-math et -fsignaling-nans (les 2 dernières options sont non par défaut!)

+0

Merci pour l'idée! 'no-unsafe-math-optimizations' est défini par défaut, mais j'ai essayé ce que vous avez suggéré et défini explicitement, mais cela n'a pas fait de différence. – Boinst

+0

J'ai "accepté" cette réponse pour l'instant, je pense qu'elle répond à ma question même si malheureusement pour moi cela n'a pas résolu mon problème. :( – Boinst

+0

Désolé d'entendre ça, j'espère que quelqu'un d'autre pourrait avoir une meilleure idée –

4

Je ne pense pas qu'il y ait un équivalent exact. Vous pouvez essayer -mfpmath=sse au lieu du -mfpmath=387 par défaut pour voir si cela aide.

+0

Je vais essayer cette solution! – Boinst

+0

Cela n'a pas aidé :(mais merci pour l'idée! – Boinst

+0

Lequel dois-je utiliser '-mfpmath = sse' ou' -ffloat-store' résout mon problème. – EmptyData

17

De l'GCC manual:

-ffloat magasin Ne pas stocker les variables à virgule flottante dans les registres, et empêcher d'autres options qui pourraient changer si une valeur en virgule flottante est tirée d'un registre ou de la mémoire.

Cette option empêche l'excès de précision indésirable sur les machines telles que le 68000 où les registres flottants (du 68881) conservent plus de précision qu'un double est censé avoir. De même pour l'architecture x86. Pour la plupart des programmes, l'excès de précision ne fait que du bien, mais quelques programmes reposent sur la définition précise du point flottant IEEE. Utilisez -ffloat-store pour ces programmes, après les avoir modifiés pour stocker tous les calculs intermédiaires pertinents dans des variables.

Pour développer un peu, la plupart de ces écarts proviennent de l'utilisation des registres à virgule flottante x86 80 bits pour les calculs (par rapport à 64 bits utilisés pour stocker double valeurs).Si les résultats intermédiaires sont conservés dans les registres sans réécrire en mémoire, vous obtenez effectivement 16 bits de précision supplémentaire dans vos calculs, les rendant plus précis mais éventuellement divergents des résultats générés par l'écriture/lecture des valeurs intermédiaires à la mémoire (ou des calculs sur architectures qui n'ont que des registres FP 64 bits). Ces indicateurs (à la fois dans GCC et MSVC) forcent généralement la troncature de chaque résultat intermédiaire à 64 bits, rendant ainsi les calculs insensibles aux aléas de la génération de code et de l'optimisation et des différences de plate-forme. Cette cohérence s'accompagne généralement d'un léger coût d'exécution en plus du coût en termes de précision/précision.

+0

Je vais essayer tout de suite – Boinst

+0

Cela ne s'est pas avéré être le problème, mais merci pour votre réponse bien pensée. Votre lien a été très utile – Boinst

+0

Désolé de l'entendre. Peut-être que cela a quelque chose à voir avec les modes d'arrondi? Vous pouvez jeter un coup d'oeil à l'assemblage généré pour un programme minimal pour lequel vous obtenez des résultats divergents et voir si la FPU est configurée différemment dans MSVC par rapport à GCC. Ensuite, vous pouvez essayer de mapper ces paramètres FPU à différents drapeaux de compilation jusqu'à ce que vous trouviez le drapeau magique. –

1

Ceci n'est certainement pas lié aux indicateurs d'optimisation, en supposant que "Debug" signifie "avec des optimisations désactivées". Si g ++ donne les mêmes résultats dans le débogage que dans la version, cela signifie que ce n'est pas un problème lié à l'optimisation. Les versions de débogage doivent toujours stocker chaque résultat intermédiaire en mémoire, garantissant ainsi les mêmes résultats que/fp: précise pour MSVC.

Cela signifie probablement qu'il y a (a) un bogue de compilateur dans l'un des compilateurs, ou plus probablement (b) un bogue de bibliothèque mathématique. Je voudrais percer dans des fonctions individuelles dans votre calcul et affiner où l'écart réside. Vous trouverez probablement une solution de contournement à ce stade, et si vous trouvez un bug, je suis sûr que l'équipe concernée aimerait en entendre parler.

+0

Merci Drew, je pense que vous avez raison, et je ferai ce que vous suggérez – Boinst

0

-mpc32 ou -mpc64?

Mais vous devrez peut-être recompiler les bibliothèques C et mathématiques avec le commutateur pour voir la différence ... Ceci peut s'appliquer aux options suggérées par d'autres.